<commit_before>/**
 * @typedef {import('unist').Node} Node
 * @typedef {import('unist').Position} Position
 * @typedef {import('unist').Point} Point
 * @typedef {Record<string, unknown> & {type: string, position?: Position|undefined}} NodeLike
 * @typedef {import('./minurl.shared.js').URL} URL
 * @typedef {import('../index.js').Data} Data
 * @typedef {import('../index.js').Value} Value
 *
 * @typedef {'ascii'|'utf8'|'utf-8'|'utf16le'|'ucs2'|'ucs-2'|'base64'|'base64url'|'latin1'|'binary'|'hex'} BufferEncoding
 *   Encodings supported by the buffer class.
 *   This is a copy of the typing from Node, copied to prevent Node globals from
 *   being needed.
 *   Copied from: <https://github.com/DefinitelyTyped/DefinitelyTyped/blob/90a4ec8/types/node/buffer.d.ts#L170>
 *
 * @typedef {Value|Options|VFile|URL} Compatible
 *   Things that can be passed to the constructor.
 *
 * @typedef VFileCoreOptions
 * @property {Value} [value]
 * @property {string} [cwd]
 * @property {Array<string>} [history]
 * @property {string|URL} [path]
 * @property {string} [basename]
 * @property {string} [stem]
 * @property {string} [extname]
 * @property {string} [dirname]
 * @property {Data} [data]
 *
 * @typedef Map
 *   Raw source map, see:
 *   <https://github.com/mozilla/source-map/blob/58819f0/source-map.d.ts#L15-L23>.
 * @property {number} version
 * @property {Array<string>} sources
 * @property {Array<string>} names
 * @property {string|undefined} [sourceRoot]
 * @property {Array<string>|undefined} [sourcesContent]
 * @property {string} mappings
 * @property {string} file
 *
 * @typedef {{[key: string]: unknown} & VFileCoreOptions} Options
 *   Configuration: a bunch of keys that will be shallow copied over to the new
 *   file.
 *
 * @typedef {Record<string, unknown>} ReporterSettings
 * @typedef {<T = ReporterSettings>(files: Array<VFile>, options: T) => string} Reporter
 */

import buffer from 'is-buffer'
import {VFileMessage} from 'vfile-message'
import {path} from './minpath.js'
import {proc} from './minproc.js'
import {urlToPath, isUrl} from './minurl.js'

// Order of setting (least specific to most), we need this because otherwise
// `{stem: 'a', path: '~/b.js'}` would throw, as a path is needed before a
// stem can be set.
const order = ['history', 'path', 'basename', 'stem', 'extname', 'dirname']

export class VFile {
  /**
   * Create a new virtual file.
   *
   * If `options` is `string` or `Buffer`, it’s treated as `{value: options}`.
   * If `options` is a `URL`, it’s treated as `{path: options}`.
   * If `options` is a `VFile`, shallow copies its data over to the new file.
   * All fields in `options` are set on the newly created `VFile`.
   *
   * Path related fields are set in the following order (least specific to
   * most specific): `history`, `path`, `basename`, `stem`, `extname`,
   * `dirname`.
   *
   * It’s not possible to set either `dirname` or `extname` without setting
   * either `history`, `path`, `basename`, or `stem` as well.
   *
   * @param {Compatible} [value]
   */
  constructor(value) {
    /** @type {Options} */
    let options

    if (!value) {
      options = {}
    } else if (typeof value === 'string' || buffer(value)) {
      // @ts-expect-error Looks like a buffer.
      options = {value}
    } else if (isUrl(value)) {
      options = {path: value}
    } else {
      // @ts-expect-error Looks like file or options.
      options = value
    }

    /**
     * Place to store custom information (default: `{}`).
     * It’s OK to store custom data directly on the file but moving it to
     * `data` is recommended.
     * @type {Data}
     */
    this.data = {}

    /**
     * List of messages associated with the file.
     * @type {Array<VFileMessage>}
     */
    this.messages = []

    /**
     * List of filepaths the file moved between.
     * The first is the original path and the last is the current path.
     * @type {Array<string>}
     */
    this.history = []

    /**
     * Base of `path` (default: `process.cwd()` or `'/'` in browsers).
     * @type {string}
     */
    this.cwd = proc.cwd()

    /* eslint-disable no-unused-expressions */
    /**
     * Raw value.
     * @type {Value}
     */
    this.value

    // The below are non-standard, they are “well-known”.
    // As in, used in several tools.

    /**
     * Whether a file was saved to disk.
     * This is used by vfile reporters.
     * @type {boolean}
     */
    this.stored

    /**
     * Sometimes files have a non-string, compiled, representation.
     * This can be stored in the `result` field.
     * One example is when turning markdown into React nodes.
     * This is used by unified to store non-string results.
     * @type {unknown}
     */
    this.result

    /**
     * Sometimes files have a source map associated with them.
     * This can be stored in the `map` field.
     * This should be a `Map` type, which is equivalent to the `RawSourceMap`
     * type from the `source-map` module.
     * @type {Map|undefined}
     */
    this.map
    /* eslint-enable no-unused-expressions */

    // Set path related properties in the correct order.
    let index = -1

    while (++index < order.length) {
      const prop = order[index]

      // Note: we specifically use `in` instead of `hasOwnProperty` to accept
      // `vfile`s too.
      if (prop in options && options[prop] !== undefined) {
        // @ts-expect-error: TS is confused by the different types for `history`.
        this[prop] = prop === 'history' ? [...options[prop]] : options[prop]
      }
    }

    /** @type {string} */
    let prop

    // Set non-path related properties.
    for (prop in options) {
      // @ts-expect-error: fine to set other things.
      if (!order.includes(prop)) this[prop] = options[prop]
    }
  }

  /**
   * Get the full path (example: `'~/index.min.js'`).
   * @returns {string}
   */
  get path() {
    return this.history[this.history.length - 1]
  }

  /**
   * Set the full path (example: `'~/index.min.js'`).
   * Cannot be nullified.
   * You can set a file URL (a `URL` object with a `file:` protocol) which will
   * be turned into a path with `url.fileURLToPath`.
   * @param {string|URL} path
   */
  set path(path) {
    if (isUrl(path)) {
      path = urlToPath(path)
    }

    assertNonEmpty(path, 'path')

    if (this.path !== path) {
      this.history.push(path)
    }
  }

  /**
   * Get the parent path (example: `'~'`).
   */
  get dirname() {
    return typeof this.path === 'string' ? path.dirname(this.path) : undefined
  }

  /**
   * Set the parent path (example: `'~'`).
   * Cannot be set if there’s no `path` yet.
   */
  set dirname(dirname) {
    assertPath(this.basename, 'dirname')
    this.path = path.join(dirname || '', this.basename)
  }

  /**
   * Get the basename (including extname) (example: `'index.min.js'`).
   */
  get basename() {
    return typeof this.path === 'string' ? path.basename(this.path) : undefined
  }

  /**
   * Set basename (including extname) (`'index.min.js'`).
   * Cannot contain path separators (`'/'` on unix, macOS, and browsers, `'\'`
   * on windows).
   * Cannot be nullified (use `file.path = file.dirname` instead).
   */
  set basename(basename) {
    assertNonEmpty(basename, 'basename')
    assertPart(basename, 'basename')
    this.path = path.join(this.dirname || '', basename)
  }

  /**
   * Get the extname (including dot) (example: `'.js'`).
   */
  get extname() {
    return typeof this.path === 'string' ? path.extname(this.path) : undefined
  }

  /**
   * Set the extname (including dot) (example: `'.js'`).
   * Cannot contain path separators (`'/'` on unix, macOS, and browsers, `'\'`
   * on windows).
   * Cannot be set if there’s no `path` yet.
   */
  set extname(extname) {
    assertPart(extname, 'extname')
    assertPath(this.dirname, 'extname')

    if (extname) {
      if (extname.charCodeAt(0) !== 46 /* `.` */) {
        throw new Error('`extname` must start with `.`')
      }

      if (extname.includes('.', 1)) {
        throw new Error('`extname` cannot contain multiple dots')
      }
    }

    this.path = path.join(this.dirname, this.stem + (extname || ''))
  }

  /**
   * Get the stem (basename w/o extname) (example: `'index.min'`).
   */
  get stem() {
    return typeof this.path === 'string'
      ? path.basename(this.path, this.extname)
      : undefined
  }

  /**
   * Set the stem (basename w/o extname) (example: `'index.min'`).
   * Cannot contain path separators (`'/'` on unix, macOS, and browsers, `'\'`
   * on windows).
   * Cannot be nullified (use `file.path = file.dirname` instead).
   */
  set stem(stem) {
    assertNonEmpty(stem, 'stem')
    assertPart(stem, 'stem')
    this.path = path.join(this.dirname || '', stem + (this.extname || ''))
  }

  /**
   * Serialize the file.
   *
   * @param {BufferEncoding} [encoding='utf8']
   *   When `value` is a `Buffer`, `encoding` is a character encoding to
   *   understand it as (default: `'utf8'`).
   * @returns {string}
   *   Serialized file.
   */
  toString(encoding) {
    return (this.value || '').toString(encoding)
  }

  /**
   * Constructs a new `VFileMessage`, where `fatal` is set to `false`, and
   * associates it with the file by adding it to `vfile.messages` and setting
   * `message.file` to the current filepath.
   *
   * @param {string|Error} reason
   *   Human readable reason for the message, uses the stack and message of the error if given.
   * @param {Node|NodeLike|Position|Point} [place]
   *   Place where the message occurred in the file.
   * @param {string} [origin]
   *   Computer readable reason for the message
   * @returns {VFileMessage}
   *   Message.
   */
  message(reason, place, origin) {
    const message = new VFileMessage(reason, place, origin)

    if (this.path) {
      message.name = this.path + ':' + message.name
      message.file = this.path
    }

    message.fatal = false

    this.messages.push(message)

    return message
  }

  /**
   * Like `VFile#message()`, but associates an informational message where
   * `fatal` is set to `null`.
   *
   * @param {string|Error} reason
   *   Human readable reason for the message, uses the stack and message of the error if given.
   * @param {Node|NodeLike|Position|Point} [place]
   *   Place where the message occurred in the file.
   * @param {string} [origin]
   *   Computer readable reason for the message
   * @returns {VFileMessage}
   *   Message.
   */
  info(reason, place, origin) {
    const message = this.message(reason, place, origin)

    message.fatal = null

    return message
  }

  /**
   * Like `VFile#message()`, but associates a fatal message where `fatal` is
   * set to `true`, and then immediately throws it.
   *
   * > 👉 **Note**: a fatal error means that a file is no longer processable.
   *
   * @param {string|Error} reason
   *   Human readable reason for the message, uses the stack and message of the error if given.
   * @param {Node|NodeLike|Position|Point} [place]
   *   Place where the message occurred in the file.
   * @param {string} [origin]
   *   Computer readable reason for the message
   * @returns {never}
   *   Message.
   */
  fail(reason, place, origin) {
    const message = this.message(reason, place, origin)

    message.fatal = true

    throw message
  }
}

/**
 * Assert that `part` is not a path (as in, does not contain `path.sep`).
 *
 * @param {string|undefined} part
 * @param {string} name
 * @returns {void}
 */
function assertPart(part, name) {
  if (part && part.includes(path.sep)) {
    throw new Error(
      '`' + name + '` cannot be a path: did not expect `' + path.sep + '`'
    )
  }
}

/**
 * Assert that `part` is not empty.
 *
 * @param {string|undefined} part
 * @param {string} name
 * @returns {asserts part is string}
 */
function assertNonEmpty(part, name) {
  if (!part) {
    throw new Error('`' + name + '` cannot be empty')
  }
}

/**
 * Assert `path` exists.
 *
 * @param {string|undefined} path
 * @param {string} name
 * @returns {asserts path is string}
 */
function assertPath(path, name) {
  if (!path) {
    throw new Error('Setting `' + name + '` requires `path` to be set too')
  }
}
<commit_msg>Add support for passing `VFileMessage` to `message` in types<commit_after>/**
 * @typedef {import('unist').Node} Node
 * @typedef {import('unist').Position} Position
 * @typedef {import('unist').Point} Point
 * @typedef {Record<string, unknown> & {type: string, position?: Position|undefined}} NodeLike
 * @typedef {import('./minurl.shared.js').URL} URL
 * @typedef {import('../index.js').Data} Data
 * @typedef {import('../index.js').Value} Value
 *
 * @typedef {'ascii'|'utf8'|'utf-8'|'utf16le'|'ucs2'|'ucs-2'|'base64'|'base64url'|'latin1'|'binary'|'hex'} BufferEncoding
 *   Encodings supported by the buffer class.
 *   This is a copy of the typing from Node, copied to prevent Node globals from
 *   being needed.
 *   Copied from: <https://github.com/DefinitelyTyped/DefinitelyTyped/blob/90a4ec8/types/node/buffer.d.ts#L170>
 *
 * @typedef {Value|Options|VFile|URL} Compatible
 *   Things that can be passed to the constructor.
 *
 * @typedef VFileCoreOptions
 * @property {Value} [value]
 * @property {string} [cwd]
 * @property {Array<string>} [history]
 * @property {string|URL} [path]
 * @property {string} [basename]
 * @property {string} [stem]
 * @property {string} [extname]
 * @property {string} [dirname]
 * @property {Data} [data]
 *
 * @typedef Map
 *   Raw source map, see:
 *   <https://github.com/mozilla/source-map/blob/58819f0/source-map.d.ts#L15-L23>.
 * @property {number} version
 * @property {Array<string>} sources
 * @property {Array<string>} names
 * @property {string|undefined} [sourceRoot]
 * @property {Array<string>|undefined} [sourcesContent]
 * @property {string} mappings
 * @property {string} file
 *
 * @typedef {{[key: string]: unknown} & VFileCoreOptions} Options
 *   Configuration: a bunch of keys that will be shallow copied over to the new
 *   file.
 *
 * @typedef {Record<string, unknown>} ReporterSettings
 * @typedef {<T = ReporterSettings>(files: Array<VFile>, options: T) => string} Reporter
 */

import buffer from 'is-buffer'
import {VFileMessage} from 'vfile-message'
import {path} from './minpath.js'
import {proc} from './minproc.js'
import {urlToPath, isUrl} from './minurl.js'

// Order of setting (least specific to most), we need this because otherwise
// `{stem: 'a', path: '~/b.js'}` would throw, as a path is needed before a
// stem can be set.
const order = ['history', 'path', 'basename', 'stem', 'extname', 'dirname']

export class VFile {
  /**
   * Create a new virtual file.
   *
   * If `options` is `string` or `Buffer`, it’s treated as `{value: options}`.
   * If `options` is a `URL`, it’s treated as `{path: options}`.
   * If `options` is a `VFile`, shallow copies its data over to the new file.
   * All fields in `options` are set on the newly created `VFile`.
   *
   * Path related fields are set in the following order (least specific to
   * most specific): `history`, `path`, `basename`, `stem`, `extname`,
   * `dirname`.
   *
   * It’s not possible to set either `dirname` or `extname` without setting
   * either `history`, `path`, `basename`, or `stem` as well.
   *
   * @param {Compatible} [value]
   */
  constructor(value) {
    /** @type {Options} */
    let options

    if (!value) {
      options = {}
    } else if (typeof value === 'string' || buffer(value)) {
      // @ts-expect-error Looks like a buffer.
      options = {value}
    } else if (isUrl(value)) {
      options = {path: value}
    } else {
      // @ts-expect-error Looks like file or options.
      options = value
    }

    /**
     * Place to store custom information (default: `{}`).
     * It’s OK to store custom data directly on the file but moving it to
     * `data` is recommended.
     * @type {Data}
     */
    this.data = {}

    /**
     * List of messages associated with the file.
     * @type {Array<VFileMessage>}
     */
    this.messages = []

    /**
     * List of filepaths the file moved between.
     * The first is the original path and the last is the current path.
     * @type {Array<string>}
     */
    this.history = []

    /**
     * Base of `path` (default: `process.cwd()` or `'/'` in browsers).
     * @type {string}
     */
    this.cwd = proc.cwd()

    /* eslint-disable no-unused-expressions */
    /**
     * Raw value.
     * @type {Value}
     */
    this.value

    // The below are non-standard, they are “well-known”.
    // As in, used in several tools.

    /**
     * Whether a file was saved to disk.
     * This is used by vfile reporters.
     * @type {boolean}
     */
    this.stored

    /**
     * Sometimes files have a non-string, compiled, representation.
     * This can be stored in the `result` field.
     * One example is when turning markdown into React nodes.
     * This is used by unified to store non-string results.
     * @type {unknown}
     */
    this.result

    /**
     * Sometimes files have a source map associated with them.
     * This can be stored in the `map` field.
     * This should be a `Map` type, which is equivalent to the `RawSourceMap`
     * type from the `source-map` module.
     * @type {Map|undefined}
     */
    this.map
    /* eslint-enable no-unused-expressions */

    // Set path related properties in the correct order.
    let index = -1

    while (++index < order.length) {
      const prop = order[index]

      // Note: we specifically use `in` instead of `hasOwnProperty` to accept
      // `vfile`s too.
      if (prop in options && options[prop] !== undefined) {
        // @ts-expect-error: TS is confused by the different types for `history`.
        this[prop] = prop === 'history' ? [...options[prop]] : options[prop]
      }
    }

    /** @type {string} */
    let prop

    // Set non-path related properties.
    for (prop in options) {
      // @ts-expect-error: fine to set other things.
      if (!order.includes(prop)) this[prop] = options[prop]
    }
  }

  /**
   * Get the full path (example: `'~/index.min.js'`).
   * @returns {string}
   */
  get path() {
    return this.history[this.history.length - 1]
  }

  /**
   * Set the full path (example: `'~/index.min.js'`).
   * Cannot be nullified.
   * You can set a file URL (a `URL` object with a `file:` protocol) which will
   * be turned into a path with `url.fileURLToPath`.
   * @param {string|URL} path
   */
  set path(path) {
    if (isUrl(path)) {
      path = urlToPath(path)
    }

    assertNonEmpty(path, 'path')

    if (this.path !== path) {
      this.history.push(path)
    }
  }

  /**
   * Get the parent path (example: `'~'`).
   */
  get dirname() {
    return typeof this.path === 'string' ? path.dirname(this.path) : undefined
  }

  /**
   * Set the parent path (example: `'~'`).
   * Cannot be set if there’s no `path` yet.
   */
  set dirname(dirname) {
    assertPath(this.basename, 'dirname')
    this.path = path.join(dirname || '', this.basename)
  }

  /**
   * Get the basename (including extname) (example: `'index.min.js'`).
   */
  get basename() {
    return typeof this.path === 'string' ? path.basename(this.path) : undefined
  }

  /**
   * Set basename (including extname) (`'index.min.js'`).
   * Cannot contain path separators (`'/'` on unix, macOS, and browsers, `'\'`
   * on windows).
   * Cannot be nullified (use `file.path = file.dirname` instead).
   */
  set basename(basename) {
    assertNonEmpty(basename, 'basename')
    assertPart(basename, 'basename')
    this.path = path.join(this.dirname || '', basename)
  }

  /**
   * Get the extname (including dot) (example: `'.js'`).
   */
  get extname() {
    return typeof this.path === 'string' ? path.extname(this.path) : undefined
  }

  /**
   * Set the extname (including dot) (example: `'.js'`).
   * Cannot contain path separators (`'/'` on unix, macOS, and browsers, `'\'`
   * on windows).
   * Cannot be set if there’s no `path` yet.
   */
  set extname(extname) {
    assertPart(extname, 'extname')
    assertPath(this.dirname, 'extname')

    if (extname) {
      if (extname.charCodeAt(0) !== 46 /* `.` */) {
        throw new Error('`extname` must start with `.`')
      }

      if (extname.includes('.', 1)) {
        throw new Error('`extname` cannot contain multiple dots')
      }
    }

    this.path = path.join(this.dirname, this.stem + (extname || ''))
  }

  /**
   * Get the stem (basename w/o extname) (example: `'index.min'`).
   */
  get stem() {
    return typeof this.path === 'string'
      ? path.basename(this.path, this.extname)
      : undefined
  }

  /**
   * Set the stem (basename w/o extname) (example: `'index.min'`).
   * Cannot contain path separators (`'/'` on unix, macOS, and browsers, `'\'`
   * on windows).
   * Cannot be nullified (use `file.path = file.dirname` instead).
   */
  set stem(stem) {
    assertNonEmpty(stem, 'stem')
    assertPart(stem, 'stem')
    this.path = path.join(this.dirname || '', stem + (this.extname || ''))
  }

  /**
   * Serialize the file.
   *
   * @param {BufferEncoding} [encoding='utf8']
   *   When `value` is a `Buffer`, `encoding` is a character encoding to
   *   understand it as (default: `'utf8'`).
   * @returns {string}
   *   Serialized file.
   */
  toString(encoding) {
    return (this.value || '').toString(encoding)
  }

  /**
   * Constructs a new `VFileMessage`, where `fatal` is set to `false`, and
   * associates it with the file by adding it to `vfile.messages` and setting
   * `message.file` to the current filepath.
   *
   * @param {string|Error|VFileMessage} reason
   *   Human readable reason for the message, uses the stack and message of the error if given.
   * @param {Node|NodeLike|Position|Point} [place]
   *   Place where the message occurred in the file.
   * @param {string} [origin]
   *   Computer readable reason for the message
   * @returns {VFileMessage}
   *   Message.
   */
  message(reason, place, origin) {
    const message = new VFileMessage(reason, place, origin)

    if (this.path) {
      message.name = this.path + ':' + message.name
      message.file = this.path
    }

    message.fatal = false

    this.messages.push(message)

    return message
  }

  /**
   * Like `VFile#message()`, but associates an informational message where
   * `fatal` is set to `null`.
   *
   * @param {string|Error|VFileMessage} reason
   *   Human readable reason for the message, uses the stack and message of the error if given.
   * @param {Node|NodeLike|Position|Point} [place]
   *   Place where the message occurred in the file.
   * @param {string} [origin]
   *   Computer readable reason for the message
   * @returns {VFileMessage}
   *   Message.
   */
  info(reason, place, origin) {
    const message = this.message(reason, place, origin)

    message.fatal = null

    return message
  }

  /**
   * Like `VFile#message()`, but associates a fatal message where `fatal` is
   * set to `true`, and then immediately throws it.
   *
   * > 👉 **Note**: a fatal error means that a file is no longer processable.
   *
   * @param {string|Error|VFileMessage} reason
   *   Human readable reason for the message, uses the stack and message of the error if given.
   * @param {Node|NodeLike|Position|Point} [place]
   *   Place where the message occurred in the file.
   * @param {string} [origin]
   *   Computer readable reason for the message
   * @returns {never}
   *   Message.
   */
  fail(reason, place, origin) {
    const message = this.message(reason, place, origin)

    message.fatal = true

    throw message
  }
}

/**
 * Assert that `part` is not a path (as in, does not contain `path.sep`).
 *
 * @param {string|undefined} part
 * @param {string} name
 * @returns {void}
 */
function assertPart(part, name) {
  if (part && part.includes(path.sep)) {
    throw new Error(
      '`' + name + '` cannot be a path: did not expect `' + path.sep + '`'
    )
  }
}

/**
 * Assert that `part` is not empty.
 *
 * @param {string|undefined} part
 * @param {string} name
 * @returns {asserts part is string}
 */
function assertNonEmpty(part, name) {
  if (!part) {
    throw new Error('`' + name + '` cannot be empty')
  }
}

/**
 * Assert `path` exists.
 *
 * @param {string|undefined} path
 * @param {string} name
 * @returns {asserts path is string}
 */
function assertPath(path, name) {
  if (!path) {
    throw new Error('Setting `' + name + '` requires `path` to be set too')
  }
}
<|endoftext|>


<commit_before>/* eslint no-process-env: 0, no-console: 0, max-statements: 0, no-sync: 0 */
'use strict';

var argv         = require('yargs').argv,
    path         = require('path'),
    fs           = require('fs'),
    mkdirp       = require('mkdirp'),
    gulpHelp     = require('gulp-help'),
    istanbul     = require('gulp-istanbul'),
    isparta      = require('isparta'),
    mocha        = require('gulp-mocha'),
    util         = require('gulp-util'),
    _            = require('lodash'),
    styleguide   = require('./godaddy-style'),
    notifier     = require('node-notifier'),
    del          = require('del'),
    once         = require('one-time'),
    sonar        = require('gulp-sonar'),
    spawn        = require('child_process').spawn,
    shrinkwrapper= require('./shrinkwrapper');

var SOURCE_FILES = ['lib/**/*.js'],
    UNIT_FILES   = ['test/unit/**/*.js'],
    INTEGRATION_FILES = ['test/integration/**/*.js'];

var mochaIcon = require.resolve('../assets/mocha.png');

module.exports = function (gulp, options) {
  gulp = gulpHelp(gulp);

  options = _.defaultsDeep(options || {}, {
    sourceFiles: SOURCE_FILES,
    unitTestFiles: UNIT_FILES,
    integrationTestFiles: INTEGRATION_FILES,
    istanbul: {
      includeUntested: true,
      thresholds: {},
      dir: './build/coverage',
      reportOpts: { dir: './build/coverage' },
      reporters: ['lcov', 'json', 'text', 'text-summary', 'cobertura']
    },
    es6: true,
    lint: {
      eslint: {},
      jscs: {}
    },
    mocha: {
      reporter: process.env.MOCHA_REPORTER || 'spec'
    }
  });

  junitOutput(options);

  // allows command line arguments to modify the options object
  // ex: gulp test --mocha.grep @production-only --mocha.invert
  // -- options.mocha == { grep: '@production-only', invert: true }
  _.each(argv, (value, name) => {
    if (name === '_' || name === '$0') return;
    options[name] = _.merge(options[name] || {}, value);
  });

  if (!options.allowUnhandledRejections) {
    process.on('unhandledRejection', function (e) {
      // no swallowed Promise errors
      throw e;
    });
  }

  if (options.es6) {
    options.lint.es6 = true;
    options.istanbul.instrumenter = isparta.Instrumenter;
  }

  var lintOptions = options.lint;
  lintOptions.files = _.flattenDeep(lintOptions.files || [
    options.sourceFiles,
    options.unitTestFiles,
    options.integrationTestFiles,
    'index.js',
    'main.js',
    'gulpfile.js',
    'gulpfile.babel.js',
    'config/**/*.json',
    'config/**/*.js',
    'lib/**/*.json',
    'test/**/*.json'
  ]);

  lintOptions.jscs.files = _.flattenDeep(lintOptions.jscs.files || [
    options.sourceFiles,
    options.unitTestFiles,
    options.integrationTestFiles,
    'index.js',
    'main.js',
    'gulpfile.js',
    'gulpfile.babel.js',
    'config/**/*.js'
  ]);

  styleguide(gulp, lintOptions);

  gulp.task('shrinkwrap', 'Shrinkwrap the existing node modules.' +
            '--existing prevents removal of existing modules. --format rewrites the same data for structure', function () {
    shrinkwrapper({ existing: !!argv.existing, format: !!argv.format });
  });

  gulp.task('default', 'Use --no-notify to turn off OS notifications of success and failure.', ['test']);

  gulp.task('unit', 'Run unit tests', function (cb) {
    runMocha(options.unitTestFiles, cb);
  });

  gulp.task('integration', 'Run integration tests', function (cb) {
    runWithDependencyProcess(runMocha, options.integrationTestFiles, cb);
  });

  gulp.task('unit-coverage', 'Run all the unit tests with code coverage', function (cb) {
    runIstanbul(options.unitTestFiles, cb);
  });

  gulp.task('integration-coverage', 'Run all the integration tests with code coverage', function (cb) {
    runWithDependencyProcess(runIstanbul, options.integrationTestFiles, cb);
  });

  gulp.task('mocha', 'Run all tests without code coverage', function (cb) {
    runWithDependencyProcess(runMocha, _.flattenDeep([options.unitTestFiles, options.integrationTestFiles]), cb);
  });

  gulp.task('test', 'Run all the tests with code coverage', ['lint', 'unit-coverage', 'integration-coverage']);

  var description = 'Watch files for changes and invoke mocha when one changes.';
  gulp.task('watch', description, function () {
    var watchFiles = _.flattenDeep([options.sourceFiles, options.unitTestFiles, options.integrationTestFiles]);
    var watcher = gulp.watch(options.watchFiles || watchFiles);
    var testFiles = _.flattenDeep([options.unitTestFiles, options.integrationTestFiles]);

    runMocha(testFiles);

    watcher.on('change', function (event) {
      notify({
        title: 'Changed: ' + event.path,
        message: 'Running mocha...'
      });

      runMocha(testFiles);
    });
  });

  gulp.task('sonar', 'Run sonar', sonarTask);

  gulp.task('clean', 'Clean up unnecessary files', function (cb) {
    del(options.filesToClean || ['./build', '.sonar']).then(function () {
      cb();
    });
  });

  gulp.task('build', 'Run the clean and test tasks', ['clean', 'test']);

  gulp.task('full', 'Run the build and sonar tasks', ['build'], sonarTask);

  function runMocha(files, cb) {
    var done = once(cb || function () {});

    return gulp.src(files, options)
      .pipe(mocha(options.mocha))
      .on('error', function (err) {
        notify({
          title: 'Test error!',
          message: 'There was an error in the tests for ' + files + '.\n' + (err && err.stack || err),
          icon: mochaIcon
        });

        done(err);
      })
      .once('end', function () {
        notify({
          title: 'Tests complete!',
          message: 'The tests for ' + files + ' have finished.',
          icon: mochaIcon
        });

        done();
      });
  }

  function runIstanbul(files, cb) {
    var done = once(cb || function () {});
    return gulp.src(options.sourceFiles)
      .pipe(istanbul(options.istanbul))
      .pipe(istanbul.hookRequire())
      .on('finish', function () {
        runMocha(files, function (err) {
          if (err) return done(err);
        })
        .pipe(istanbul.writeReports(options.istanbul))
        .pipe(istanbul.enforceThresholds(options.istanbul))
        .on('error', function (err) {
          notify({
            title: 'Istanbul test error!',
            message: 'There was an error in the tests for ' + files + '.\n' + (err && err.stack || err)
          });
          done(err);
        })
        .once('end', function () {
          notify({
            title: 'Istanbul tests complete!',
            message: 'The tests for ' + files + ' have finished.'
          });
          done();
        });
      });
  }

  function sonarTask() {
    var config = _.merge({
      sonar: {
        host: {
          url: argv.sonarUrl || 'http://localhost:9000'
        },
        sources: 'lib',
        language: 'js',
        sourceEncoding: 'UTF-8',
        javascript: {
          lcov: {
            reportPath: './build/coverage/lcov.info'
          }
        }
      }
    }, options.sonar);

    return gulp.src('thisFileDoesNotExist.js', { read: false })
      .pipe(sonar(config))
      .on('error', util.log);
  }

  function runWithDependencyProcess(runner, files, cb) {
    var opts = options.dependencyProcess;
    if (!opts) {
      return void runner(files, cb);
    }
    return void createChildProcess(opts, function (err, child) {
      if (err) throw err;
      runner(files, function (err1) {
        child.send('close');
        cb(err1);
      })
    });
  }

  function createChildProcess(opts, cb) {
    notify({ title: opts.name, message: 'Starting...' });
    var child = spawn(opts.command, opts.args, { stdio: [process.stdin, process.stdout, process.stderr, 'ipc'] });
    child.on('message', function (data) {
      if (data === 'started') {
        return void cb(null, child);
      }
      return void 0;
    });
    child.on('error', function (err) {
      notify({ title: opts.name, message: 'Error: ' + JSON.stringify(err) });
    });
    child.on('exit', function () {
      notify({ title: opts.name, message: 'Exited' });
    });
  }
};

function notify(options) {
  util.log(options.title + ': ' + options.message);
  if (!argv.noNotify) {
    notifier.notify(options);
  }
}

function junitOutput(opts) {
  if (argv.junit) {
    // handle the test output
    var file = typeof argv.junit === 'string' ? argv.junit : (process.env.MOCHA_FILE || './build/test/test-results.xml');
    var dir = path.dirname(file);
    if (!fs.existsSync(dir)) mkdirp.sync(dir, 0o777);
    opts.mocha.reporter = 'mocha-junit-reporter';
    opts.mocha.reporterOptions = { mochaFile: file };

    // set the eslint junit handling as well
    file = typeof argv.junit === 'string' ? argv.junit : (process.env.ESLINT_FILE || './build/test/eslint-results.xml');
    dir = path.dirname(file);
    if (!fs.existsSync(dir)) mkdirp.sync(dir, 0o777);
    opts.lint.eslint.formatter = 'junit';
    opts.lint.eslint.formatterFunction = function (data) { fs.writeFile(file, data); };
  }
}

<commit_msg>Fix assignment alignment<commit_after>/* eslint no-process-env: 0, no-console: 0, max-statements: 0, no-sync: 0 */
'use strict';

var argv = require('yargs').argv;
var path = require('path');
var fs = require('fs');
var mkdirp = require('mkdirp');
var gulpHelp = require('gulp-help');
var istanbul = require('gulp-istanbul');
var isparta = require('isparta');
var mocha = require('gulp-mocha');
var util = require('gulp-util');
var _ = require('lodash');
var styleguide = require('./godaddy-style');
var notifier = require('node-notifier');
var del = require('del');
var once = require('one-time');
var sonar = require('gulp-sonar');
var spawn = require('child_process').spawn;
var shrinkwrapper= require('./shrinkwrapper');

var SOURCE_FILES = ['lib/**/*.js'],
    UNIT_FILES   = ['test/unit/**/*.js'],
    INTEGRATION_FILES = ['test/integration/**/*.js'];

var mochaIcon = require.resolve('../assets/mocha.png');

module.exports = function (gulp, options) {
  gulp = gulpHelp(gulp);

  options = _.defaultsDeep(options || {}, {
    sourceFiles: SOURCE_FILES,
    unitTestFiles: UNIT_FILES,
    integrationTestFiles: INTEGRATION_FILES,
    istanbul: {
      includeUntested: true,
      thresholds: {},
      dir: './build/coverage',
      reportOpts: { dir: './build/coverage' },
      reporters: ['lcov', 'json', 'text', 'text-summary', 'cobertura']
    },
    es6: true,
    lint: {
      eslint: {},
      jscs: {}
    },
    mocha: {
      reporter: process.env.MOCHA_REPORTER || 'spec'
    }
  });

  junitOutput(options);

  // allows command line arguments to modify the options object
  // ex: gulp test --mocha.grep @production-only --mocha.invert
  // -- options.mocha == { grep: '@production-only', invert: true }
  _.each(argv, (value, name) => {
    if (name === '_' || name === '$0') return;
    options[name] = _.merge(options[name] || {}, value);
  });

  if (!options.allowUnhandledRejections) {
    process.on('unhandledRejection', function (e) {
      // no swallowed Promise errors
      throw e;
    });
  }

  if (options.es6) {
    options.lint.es6 = true;
    options.istanbul.instrumenter = isparta.Instrumenter;
  }

  var lintOptions = options.lint;
  lintOptions.files = _.flattenDeep(lintOptions.files || [
    options.sourceFiles,
    options.unitTestFiles,
    options.integrationTestFiles,
    'index.js',
    'main.js',
    'gulpfile.js',
    'gulpfile.babel.js',
    'config/**/*.json',
    'config/**/*.js',
    'lib/**/*.json',
    'test/**/*.json'
  ]);

  lintOptions.jscs.files = _.flattenDeep(lintOptions.jscs.files || [
    options.sourceFiles,
    options.unitTestFiles,
    options.integrationTestFiles,
    'index.js',
    'main.js',
    'gulpfile.js',
    'gulpfile.babel.js',
    'config/**/*.js'
  ]);

  styleguide(gulp, lintOptions);

  gulp.task('shrinkwrap', 'Shrinkwrap the existing node modules.' +
            '--existing prevents removal of existing modules. --format rewrites the same data for structure', function () {
    shrinkwrapper({ existing: !!argv.existing, format: !!argv.format });
  });

  gulp.task('default', 'Use --no-notify to turn off OS notifications of success and failure.', ['test']);

  gulp.task('unit', 'Run unit tests', function (cb) {
    runMocha(options.unitTestFiles, cb);
  });

  gulp.task('integration', 'Run integration tests', function (cb) {
    runWithDependencyProcess(runMocha, options.integrationTestFiles, cb);
  });

  gulp.task('unit-coverage', 'Run all the unit tests with code coverage', function (cb) {
    runIstanbul(options.unitTestFiles, cb);
  });

  gulp.task('integration-coverage', 'Run all the integration tests with code coverage', function (cb) {
    runWithDependencyProcess(runIstanbul, options.integrationTestFiles, cb);
  });

  gulp.task('mocha', 'Run all tests without code coverage', function (cb) {
    runWithDependencyProcess(runMocha, _.flattenDeep([options.unitTestFiles, options.integrationTestFiles]), cb);
  });

  gulp.task('test', 'Run all the tests with code coverage', ['lint', 'unit-coverage', 'integration-coverage']);

  var description = 'Watch files for changes and invoke mocha when one changes.';
  gulp.task('watch', description, function () {
    var watchFiles = _.flattenDeep([options.sourceFiles, options.unitTestFiles, options.integrationTestFiles]);
    var watcher = gulp.watch(options.watchFiles || watchFiles);
    var testFiles = _.flattenDeep([options.unitTestFiles, options.integrationTestFiles]);

    runMocha(testFiles);

    watcher.on('change', function (event) {
      notify({
        title: 'Changed: ' + event.path,
        message: 'Running mocha...'
      });

      runMocha(testFiles);
    });
  });

  gulp.task('sonar', 'Run sonar', sonarTask);

  gulp.task('clean', 'Clean up unnecessary files', function (cb) {
    del(options.filesToClean || ['./build', '.sonar']).then(function () {
      cb();
    });
  });

  gulp.task('build', 'Run the clean and test tasks', ['clean', 'test']);

  gulp.task('full', 'Run the build and sonar tasks', ['build'], sonarTask);

  function runMocha(files, cb) {
    var done = once(cb || function () {});

    return gulp.src(files, options)
      .pipe(mocha(options.mocha))
      .on('error', function (err) {
        notify({
          title: 'Test error!',
          message: 'There was an error in the tests for ' + files + '.\n' + (err && err.stack || err),
          icon: mochaIcon
        });

        done(err);
      })
      .once('end', function () {
        notify({
          title: 'Tests complete!',
          message: 'The tests for ' + files + ' have finished.',
          icon: mochaIcon
        });

        done();
      });
  }

  function runIstanbul(files, cb) {
    var done = once(cb || function () {});
    return gulp.src(options.sourceFiles)
      .pipe(istanbul(options.istanbul))
      .pipe(istanbul.hookRequire())
      .on('finish', function () {
        runMocha(files, function (err) {
          if (err) return done(err);
        })
        .pipe(istanbul.writeReports(options.istanbul))
        .pipe(istanbul.enforceThresholds(options.istanbul))
        .on('error', function (err) {
          notify({
            title: 'Istanbul test error!',
            message: 'There was an error in the tests for ' + files + '.\n' + (err && err.stack || err)
          });
          done(err);
        })
        .once('end', function () {
          notify({
            title: 'Istanbul tests complete!',
            message: 'The tests for ' + files + ' have finished.'
          });
          done();
        });
      });
  }

  function sonarTask() {
    var config = _.merge({
      sonar: {
        host: {
          url: argv.sonarUrl || 'http://localhost:9000'
        },
        sources: 'lib',
        language: 'js',
        sourceEncoding: 'UTF-8',
        javascript: {
          lcov: {
            reportPath: './build/coverage/lcov.info'
          }
        }
      }
    }, options.sonar);

    return gulp.src('thisFileDoesNotExist.js', { read: false })
      .pipe(sonar(config))
      .on('error', util.log);
  }

  function runWithDependencyProcess(runner, files, cb) {
    var opts = options.dependencyProcess;
    if (!opts) {
      return void runner(files, cb);
    }
    return void createChildProcess(opts, function (err, child) {
      if (err) throw err;
      runner(files, function (err1) {
        child.send('close');
        cb(err1);
      })
    });
  }

  function createChildProcess(opts, cb) {
    notify({ title: opts.name, message: 'Starting...' });
    var child = spawn(opts.command, opts.args, { stdio: [process.stdin, process.stdout, process.stderr, 'ipc'] });
    child.on('message', function (data) {
      if (data === 'started') {
        return void cb(null, child);
      }
      return void 0;
    });
    child.on('error', function (err) {
      notify({ title: opts.name, message: 'Error: ' + JSON.stringify(err) });
    });
    child.on('exit', function () {
      notify({ title: opts.name, message: 'Exited' });
    });
  }
};

function notify(options) {
  util.log(options.title + ': ' + options.message);
  if (!argv.noNotify) {
    notifier.notify(options);
  }
}

function junitOutput(opts) {
  if (argv.junit) {
    // handle the test output
    var file = typeof argv.junit === 'string' ? argv.junit : (process.env.MOCHA_FILE || './build/test/test-results.xml');
    var dir = path.dirname(file);
    if (!fs.existsSync(dir)) mkdirp.sync(dir, 0o777);
    opts.mocha.reporter = 'mocha-junit-reporter';
    opts.mocha.reporterOptions = { mochaFile: file };

    // set the eslint junit handling as well
    file = typeof argv.junit === 'string' ? argv.junit : (process.env.ESLINT_FILE || './build/test/eslint-results.xml');
    dir = path.dirname(file);
    if (!fs.existsSync(dir)) mkdirp.sync(dir, 0o777);
    opts.lint.eslint.formatter = 'junit';
    opts.lint.eslint.formatterFunction = function (data) { fs.writeFile(file, data); };
  }
}

<|endoftext|>


<commit_before>/*
 * pilite
 * https://github.com/woodyrew/node-pilite
 *
 * Copyright (c) 2013 Andrew Goodricke
 * Licensed under the MIT license.
 */

'use strict';

var SerialPort = require("serialport").SerialPort;

var device   = '/dev/ttyAMA0';
var baudrate = 9600;
var client   = null;

/**
 * Initialisation function
 *
 * @return {void}
 */
var init = function () {
    client = new SerialPort(device, {
        baudrate: baudrate
    }, false);
};

/**
 * Opens a connection and runs a callback.
 *
 * @param  {Function} callback
 *
 * @return {void}
 */
var connect = function (callback) {
    init();

    client.open(function() {
      console.log('Connected to Pi Lite');

      callback();
    });
};

/**
 * Writes commands to the serial to instruct the Pi Lite
 *
 * @param  {string} data
 *
 * @return {void}
 */
var write = function (data) {
    // console.log('Writing: '+ data);
    if (client !== null) {
        client.write(data, function(err) {
            // removed results from params - add if you need to debug

            if (err) {
                console.log('Error', err);
            }

            // console.log('Result', results);
        });
    }
};

/**
 * returns a command string
 * @param  {string} code        PiLite Command Code
 * @param  {mixed} value        Command Value
 * @param  {boolean} newLine    Whether to return a new line at the end
 *
 * @return {string}
 */
var _getCommand = function (commandCode, value, newLine) {
    newLine = (typeof newLine !== 'undefined') ? newLine : true;
    return '$$$' + commandCode + value + (newLine ? "\r" : '');
}

/**
 * Gets an item's value from an object and defaults to a passed value if not present.
 *
 * @param  {object} obj             Object to search
 * @param  {mixed} item             Item to find within object
 * @param  {mixed} myDefault        Default value to provide if item's not found
 *
 * @return {mixed}
 */
var _getItemValue = function (obj, item, myDefault) {
    return (obj && typeof obj[item] !== 'undefined') ? obj[item] : myDefault;
};

/**
 * Generally the process that needs to occur
 * @see The Pi-Lite pre-loaded software commands.
 *
 * @param  {string} commandCode     Code for the Pi Lite to process see url
 * @param  {mixed} value            Value to apply to the command
 * @param  {object} options         Options that might be required
 *
 * @return {string}
 */
var _processCommand = function (commandCode, value, options) {
    var runCommand = _getItemValue(options, 'runCommand', true),
        newLine = _getItemValue(options, 'newLine', true),
        command = _getCommand(commandCode, value, newLine);

    if (runCommand) {
        write(command);
    }
    return command;
};

/**
 * Set scrolling delay in ms 1 is scrolling very fast, 1000 is scrolling very slow. Default speed is 80.
 *
 * @param {integer} value
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var setSpeed = function (value, options) {
    return _processCommand('SPEED', value, options);
};

/**
 * Sets a frame instantly in one go.
 * Using a 126 character string in ones and zeros to represent each LED state (on or off)
 *
 * @param {string} value        126 char string
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var frameBuffer = function (value, options) {
    if (value.length !== 126) {
        throw new Error('String should be 126 characters long');
    }
    else if (/[^01]+/.test(value)) {
        throw new Error('String should only contain zeros and ones');
    }

    return _processCommand('F', value, options);
};

/**
 * Sets a column to a percentage
 *
 * @param {integer} column      1-14
 * @param {integer} value       percentage
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var barGraph = function (column, value, options) {
    if (column < 1 || column > 14) {
        throw new Error('The value of the column should be between 1-14 (inclusive)');
    }
    value = Math.round(value);
    if (value < 0 || value > 100) {
        throw new Error('The percentage should be between 0-100 (inclusive)');
    }

    return _processCommand('B', column + "," + value, options);
};

/**
 * Create graph from an array (max 14 columns)
 *
 * @param {array} data          array of percentage values, array length should be 14 or less
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var chart = function (data, options) {
    var that = this,
        command = '';

    data.forEach(function(graphValue, index) {
        command += that.barGraph(index + 1, graphValue, options);
    });
    return command;
};

/**
 * vuMeter - Horizontal bar graph
 *
 * @param  {integer} row        1 or 2
 * @param  {integer} value      Percentage 0-100
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var vuMeter = function (row, value, options) {
    if (row < 1 || row > 2) {
        throw new Error('The value of the row should be between 1-2 (inclusive)');
    }
    value = Math.round(value);
    if (value < 0 || value > 100) {
        throw new Error('The percentage should be between 0-100 (inclusive)');
    }

    return _processCommand('V', row + "," + value, options);
};

/**
 * Set a pixel's state
 *
 * @param  {integer} column     1 to 14
 * @param  {integer} row        1 to 9
 * @param  {string} action      ON, OFF or TOGGLE (Toggle will turn it off if it's on and visa versa)
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var pixel = function (column, row, action, options) {
    if (column < 1 || column > 14) {
        throw new Error('The value of the column should be between 1-14 (inclusive)');
    }
    if (row < 1 || row > 9) {
        throw new Error('The value of the row should be between 1-9 (inclusive)');
    }
    if (action !== 'ON' && action !== 'OFF' && action !== 'TOGGLE') {
        throw new Error("The value of the action should be ON, OFF or TOGGLE");
    }

    return _processCommand('P', column + "," + row + "," + action, options);
};

/**
 * set all the pixels on or off
 *
 * @param  {string} value       ON or OFF
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var all = function (value, options) {
    return _processCommand('ALL', "," + value, options);
};

/**
 * Turns all pixels off - Alias to ALL,OFF
 *
 * @return {string}
 */
var clear = function (options) {
    return all("OFF", options);
};

/**
 * Scroll value columns left (+) or right (-)
 *
 * @param  {integer} value      -14 and 14 but not zero
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var scroll = function (value, options) {
    if (value < -14 || value > 14 || value === 0) {
        throw new Error('The value should be between -14 and 14 but not zero (inclusive)');
    }

    return _processCommand('SCROLL', value, options);
};

/**
 * Display character at location x,y.
 *
 * @param  {integer} column     1-14
 * @param  {integer} row        1-9
 * @param  {sting} character    ASCII
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var text = function (column, row, character, options) {
    write("$$$T"+ column +","+ row +","+ character +"\r");
    return _processCommand('T', column + "," + row + "," + character, options);
};

// Set methods to export
var pilite = {
    connect      : connect
  , write      : write
  , setSpeed   : setSpeed
  , frameBuffer: frameBuffer
  , barGraph   : barGraph
  , chart      : chart
  , vuMeter    : vuMeter
  , pixel      : pixel
  , all        : all
  , clear      : clear
  , scroll     : scroll
  , text       : text
};

module.exports = pilite;
<commit_msg>Lib - ESLint: Standardised<commit_after>/*
 * pilite
 * https://github.com/woodyrew/node-pilite
 *
 * Copyright (c) 2013 Andrew Goodricke
 * Licensed under the MIT license.
 */

'use strict';

var SerialPort = require('serialport').SerialPort;

var device   = '/dev/ttyAMA0';
var baudrate = 9600;
var client   = null;

/**
 * Initialisation function
 *
 * @return {void}
 */
var init = function () {
    client = new SerialPort(device, {
        baudrate: baudrate
    }, false);
};

/**
 * Opens a connection and runs a callback.
 *
 * @param  {Function} callback
 *
 * @return {void}
 */
var connect = function (callback) {
    init();

    client.open(function() {
      console.log('Connected to Pi Lite');

      callback();
    });
};

/**
 * Writes commands to the serial to instruct the Pi Lite
 *
 * @param  {string} data
 *
 * @return {void}
 */
var write = function (data) {
    // console.log('Writing: '+ data);
    if (client !== null) {
        client.write(data, function(err) {
            // removed results from params - add if you need to debug

            if (err) {
                console.log('Error', err);
            }

            // console.log('Result', results);
        });
    }
};

/**
 * returns a command string
 * @param  {string} commandCode PiLite Command Code
 * @param  {mixed} value        Command Value
 * @param  {boolean} newLine    Whether to return a new line at the end
 *
 * @return {string}
 */
var _getCommand = function (commandCode, value, newLine) {
    newLine = (typeof newLine !== 'undefined') ? newLine : true;
    return '$$$' + commandCode + value + (newLine ? '\r' : '');
}

/**
 * Gets an item's value from an object and defaults to a passed value if not present.
 *
 * @param  {object} obj             Object to search
 * @param  {mixed} item             Item to find within object
 * @param  {mixed} myDefault        Default value to provide if item's not found
 *
 * @return {mixed}
 */
var _getItemValue = function (obj, item, myDefault) {
    return (obj && typeof obj[item] !== 'undefined') ? obj[item] : myDefault;
};

/**
 * Generally the process that needs to occur
 * @see The Pi-Lite pre-loaded software commands.
 *
 * @param  {string} commandCode     Code for the Pi Lite to process see url
 * @param  {mixed} value            Value to apply to the command
 * @param  {object} options         Options that might be required
 *
 * @return {string}
 */
var _processCommand = function (commandCode, value, options) {
    var runCommand = _getItemValue(options, 'runCommand', true);
    var newLine    = _getItemValue(options, 'newLine', true);
    var command    = _getCommand(commandCode, value, newLine);

    if (runCommand) {
        write(command);
    }
    return command;
};

/**
 * Set scrolling delay in ms 1 is scrolling very fast, 1000 is scrolling very slow. Default speed is 80.
 *
 * @param {integer} value
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var setSpeed = function (value, options) {
    return _processCommand('SPEED', value, options);
};

/**
 * Sets a frame instantly in one go.
 * Using a 126 character string in ones and zeros to represent each LED state (on or off)
 *
 * @param {string} value        126 char string
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var frameBuffer = function (value, options) {
    if (value.length !== 126) {
        throw new Error('String should be 126 characters long');
    }
    else if (/[^01]+/.test(value)) {
        throw new Error('String should only contain zeros and ones');
    }

    return _processCommand('F', value, options);
};

/**
 * Sets a column to a percentage
 *
 * @param {integer} column      1-14
 * @param {integer} value       percentage
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var barGraph = function (column, value, options) {
    if (column < 1 || column > 14) {
        throw new Error('The value of the column should be between 1-14 (inclusive)');
    }
    value = Math.round(value);
    if (value < 0 || value > 100) {
        throw new Error('The percentage should be between 0-100 (inclusive)');
    }

    return _processCommand('B', column + ',' + value, options);
};

/**
 * Create graph from an array (max 14 columns)
 *
 * @param {array} data          array of percentage values, array length should be 14 or less
 * @param {object} options      See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var chart = function (data, options) {
    var that = this;
    var command = '';

    data.forEach(function(graphValue, index) {
        command += that.barGraph(index + 1, graphValue, options);
    });
    return command;
};

/**
 * vuMeter - Horizontal bar graph
 *
 * @param  {integer} row        1 or 2
 * @param  {integer} value      Percentage 0-100
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var vuMeter = function (row, value, options) {
    if (row < 1 || row > 2) {
        throw new Error('The value of the row should be between 1-2 (inclusive)');
    }
    value = Math.round(value);
    if (value < 0 || value > 100) {
        throw new Error('The percentage should be between 0-100 (inclusive)');
    }

    return _processCommand('V', row + ',' + value, options);
};

/**
 * Set a pixel's state
 *
 * @param  {integer} column     1 to 14
 * @param  {integer} row        1 to 9
 * @param  {string} action      ON, OFF or TOGGLE (Toggle will turn it off if it's on and visa versa)
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var pixel = function (column, row, action, options) {
    if (column < 1 || column > 14) {
        throw new Error('The value of the column should be between 1-14 (inclusive)');
    }
    if (row < 1 || row > 9) {
        throw new Error('The value of the row should be between 1-9 (inclusive)');
    }
    if (action !== 'ON' && action !== 'OFF' && action !== 'TOGGLE') {
        throw new Error('The value of the action should be ON, OFF or TOGGLE');
    }

    return _processCommand('P', column + ',' + row + ',' + action, options);
};

/**
 * set all the pixels on or off
 *
 * @param  {string} value       ON or OFF
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var all = function (value, options) {
    return _processCommand('ALL', ',' + value, options);
};

/**
 * Turns all pixels off - Alias to ALL,OFF
 *
 * @param {object} options  See {@link _processCommand} for options
 *
 * @return {string}
 */
var clear = function (options) {
    return all('OFF', options);
};

/**
 * Scroll value columns left (+) or right (-)
 *
 * @param  {integer} value      -14 and 14 but not zero
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var scroll = function (value, options) {
    if (value < -14 || value > 14 || value === 0) {
        throw new Error('The value should be between -14 and 14 but not zero (inclusive)');
    }

    return _processCommand('SCROLL', value, options);
};

/**
 * Display character at location x,y.
 *
 * @param  {integer} column     1-14
 * @param  {integer} row        1-9
 * @param  {sting} character    ASCII
 * @param  {object} options     See {@link _processCommand} for options
 *
 * @return {string}             Command to perform required action
 */
var text = function (column, row, character, options) {
    write('$$$T'+ column + ',' + row + ',' + character + '\r');
    return _processCommand('T', column + ',' + row + ',' + character, options);
};

// Set methods to export
var pilite = {
    connect      : connect
  , write      : write
  , setSpeed   : setSpeed
  , frameBuffer: frameBuffer
  , barGraph   : barGraph
  , chart      : chart
  , vuMeter    : vuMeter
  , pixel      : pixel
  , all        : all
  , clear      : clear
  , scroll     : scroll
  , text       : text
};

module.exports = pilite;
<|endoftext|>


<commit_before>'use strict';
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const webpackOptionsMerge = require('webpack-loader-options-merge');
const chalk = require('chalk');
const util = require('./util');
const inspect = require('util').inspect;

const DEFAULT_OPTIONS = {
  verbose: true,
  debug: false
};

module.exports = class FrontPack {
  constructor(option) {
    this._packOption = Object.assign({},DEFAULT_OPTIONS,option);
    this._strategy = {};
    this._config = [];
    this._preset = [];
    this._presetOption = {};
    this._option = {};
  }

  _generatePresetPath(preset) {
    return this._generatePath('preset', preset);
  }
  _generatePath(prefix,name) {
    return [
      path.join(`${name}`),
      path.join(`frontpack-${prefix}-${name}`),
      path.join(`@frontpack/frontpack-${prefix}-${name}`)
    ];
  }
  _arrayUnique(arr) {
    return arr.filter(function (name, i, self) {
      return self.indexOf(name) === i;
    });
  }

  config(...customConfig) {
    this._config = this._config.concat(customConfig);
    return this;
  }

  /**
   * presetからまとめて設定する
   * @param presets
   * @param presetOptions
   * @returns {FrontPack}
   */
  preset(presets, presetOptions) {
    this._preset = this._preset.concat(presets);
    this._presetOption = Object.assign(this._presetOption, presetOptions);
    return this;
  }

  /**
   * マージのルールを設定
   * @param strategy
   * @returns {FrontPack}
   */
  strategy(strategy) {
    this._strategy = strategy;
    return this;
  }

  /**
   * Loaderのオプションを設定
   * @param options
   * @returns {FrontPack}
   */
  option(options) {
    this._option = Object.assign(this._option, options);
    return this;
  }

  /**
   * webpack.configを生成して返却
   */
  export() {
    let config = {
      plugins: []
    };
    let merge = webpackMerge.strategy(this._strategy);

    // 重複指定を削除
    this._preset = this._arrayUnique(this._preset);
    // プリセットの設定を取り込む
    this._preset.forEach((preset) => {
      config = merge(config,util.require(this._generatePresetPath(preset))(this._option[preset],config));
    });

    // 外部からのconfigをマージする
    this._config.forEach((conf) => {
      config = merge(config, conf);
    });

    // オプションの定義
    config.plugins.push(
      new webpack.LoaderOptionsPlugin(this._option)
    );

    if (this._packOption.verbose || this._packOption.debug) {
      console.log(chalk.green('- frontpack -'));
      if (this._preset.length > 0) {
        console.log(chalk.green(`preset:`), `[${this._preset.join(',')}]`);
      } else {
        console.log(chalk.green(`preset:`), `no set`);
      }
    }

    let result = webpackOptionsMerge(config);

    if (this._packOption.debug) {

      if (this._config.length > 0) {
        console.log(chalk.green(`config:`));
        this._config.forEach((c) => {
          console.log(inspect(c,false,null));
        });
      } else {
        console.log(chalk.green(`config:`), `no set`);
      }
      console.log(chalk.green(`------------------result-----------------`));
      console.log(inspect(result,false,null));
      console.log(chalk.green(`-----------------/result-----------------`));
    }
    return result;
  }
};<commit_msg>パス参照順が不正なのを修正<commit_after>'use strict';
const path = require('path');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const webpackOptionsMerge = require('webpack-loader-options-merge');
const chalk = require('chalk');
const util = require('./util');
const inspect = require('util').inspect;

const DEFAULT_OPTIONS = {
  verbose: true,
  debug: false
};

module.exports = class FrontPack {
  constructor(option) {
    this._packOption = Object.assign({},DEFAULT_OPTIONS,option);
    this._strategy = {};
    this._config = [];
    this._preset = [];
    this._presetOption = {};
    this._option = {};
  }

  _generatePresetPath(preset) {
    return [
      path.join(`@frontpack/frontpack-preset-${preset}`),
      path.join(`frontpack-preset-${preset}`),
      path.join(`${preset}`),
    ];
  }
  _arrayUnique(arr) {
    return arr.filter(function (name, i, self) {
      return self.indexOf(name) === i;
    });
  }

  config(...customConfig) {
    this._config = this._config.concat(customConfig);
    return this;
  }

  /**
   * presetからまとめて設定する
   * @param presets
   * @param presetOptions
   * @returns {FrontPack}
   */
  preset(presets, presetOptions) {
    this._preset = this._preset.concat(presets);
    this._presetOption = Object.assign(this._presetOption, presetOptions);
    return this;
  }

  /**
   * マージのルールを設定
   * @param strategy
   * @returns {FrontPack}
   */
  strategy(strategy) {
    this._strategy = strategy;
    return this;
  }

  /**
   * Loaderのオプションを設定
   * @param options
   * @returns {FrontPack}
   */
  option(options) {
    this._option = Object.assign(this._option, options);
    return this;
  }

  /**
   * webpack.configを生成して返却
   */
  export() {
    let config = {
      plugins: []
    };
    let merge = webpackMerge.strategy(this._strategy);

    // 重複指定を削除
    this._preset = this._arrayUnique(this._preset);
    // プリセットの設定を取り込む
    this._preset.forEach((preset) => {
      config = merge(config,util.require(this._generatePresetPath(preset))(this._option[preset],config));
    });

    // 外部からのconfigをマージする
    this._config.forEach((conf) => {
      config = merge(config, conf);
    });

    // オプションの定義
    config.plugins.push(
      new webpack.LoaderOptionsPlugin(this._option)
    );

    if (this._packOption.verbose || this._packOption.debug) {
      console.log(chalk.green('- frontpack -'));
      if (this._preset.length > 0) {
        console.log(chalk.green(`preset:`), `[${this._preset.join(',')}]`);
      } else {
        console.log(chalk.green(`preset:`), `no set`);
      }
    }

    let result = webpackOptionsMerge(config);

    if (this._packOption.debug) {

      if (this._config.length > 0) {
        console.log(chalk.green(`config:`));
        this._config.forEach((c) => {
          console.log(inspect(c,false,null));
        });
      } else {
        console.log(chalk.green(`config:`), `no set`);
      }
      console.log(chalk.green(`------------------result-----------------`));
      console.log(inspect(result,false,null));
      console.log(chalk.green(`-----------------/result-----------------`));
    }
    return result;
  }
};<|endoftext|>


<commit_before>'use strict';

const Boom = require('boom');
const Hoek = require('hoek');

// Declare Internals

const internals = {};

exports.register = function (server, options, next) {

    server.auth.scheme('bearer-access-token', internals.implementation);
    next();
};

exports.register.attributes = {
    pkg: require('../package.json')
};

internals.implementation = (server, options) => {

    Hoek.assert(options, 'Missing bearer auth strategy options');
    Hoek.assert(typeof options.validateFunc === 'function', 'options.validateFunc must be a valid function in bearer scheme');

    options.accessTokenName = options.accessTokenName || 'access_token';
    options.allowQueryToken = options.allowQueryToken === false ? false : true;
    options.allowMultipleHeaders = options.allowMultipleHeaders === true ? true : false;
    options.tokenType = options.tokenType || 'Bearer';

    const settings = Hoek.clone(options);

    const scheme = {
        authenticate: (request, reply) => {

            const req = request.raw.req;
            let authorization = req.headers.authorization;

            if (settings.allowQueryToken
                && !authorization
                && request.query[settings.accessTokenName] ) {
                authorization = options.tokenType + ' ' + request.query[settings.accessTokenName];
                delete request.query[settings.accessTokenName];
            }

            if (!authorization) {
                return reply(Boom.unauthorized(null, options.tokenType));
            }

            if (settings.allowMultipleHeaders) {
                const headers = authorization.match(/Bearer\s+([^;$]+)/i);
                if (headers !== null) {
                    authorization = headers[0];
                }
            }

            const parts = authorization.split(/\s+/);

            if (parts[0].toLowerCase() !== options.tokenType.toLowerCase()) {
                return reply(Boom.unauthorized(null, options.tokenType));
            }

            const token = parts[1];

            settings.validateFunc.call(request, token, (err, isValid, credentials) => {

                if (err) {
                    return reply(err, { credentials: credentials, log: { tags: ['auth', 'bearer'], data: err } });
                }

                if (!isValid) {
                    return reply(Boom.unauthorized('Bad token', options.tokenType), { credentials: credentials });
                }

                if (!credentials
                    || typeof credentials !== 'object') {
                    return reply(Boom.badImplementation('Bad token string received for Bearer auth validation'), { log: { tags: 'token' } });
                }

                return reply.continue({ credentials: credentials });
            });
        }
    };

    return scheme;
};
<commit_msg>dynamic regexp to allow renaming of token type<commit_after>'use strict';

const Boom = require('boom');
const Hoek = require('hoek');

// Declare Internals

const internals = {};

exports.register = function (server, options, next) {

    server.auth.scheme('bearer-access-token', internals.implementation);
    next();
};

exports.register.attributes = {
    pkg: require('../package.json')
};

internals.implementation = (server, options) => {

    Hoek.assert(options, 'Missing bearer auth strategy options');
    Hoek.assert(typeof options.validateFunc === 'function', 'options.validateFunc must be a valid function in bearer scheme');

    options.accessTokenName = options.accessTokenName || 'access_token';
    options.allowQueryToken = options.allowQueryToken === false ? false : true;
    options.allowMultipleHeaders = options.allowMultipleHeaders === true ? true : false;
    options.tokenType = options.tokenType || 'Bearer';

    const settings = Hoek.clone(options);

    settings.headerRegExp = new RegExp(options.tokenType + '\\s+([^;$]+)','i');

    const scheme = {
        authenticate: (request, reply) => {

            const req = request.raw.req;
            let authorization = req.headers.authorization;

            if (settings.allowQueryToken
                && !authorization
                && request.query[settings.accessTokenName] ) {
                authorization = options.tokenType + ' ' + request.query[settings.accessTokenName];
                delete request.query[settings.accessTokenName];
            }

            if (!authorization) {
                return reply(Boom.unauthorized(null, options.tokenType));
            }

            if (settings.allowMultipleHeaders) {
                const headers = authorization.match(settings.headerRegExp);
                if (headers !== null) {
                    authorization = headers[0];
                }
            }

            const parts = authorization.split(/\s+/);

            if (parts[0].toLowerCase() !== options.tokenType.toLowerCase()) {
                return reply(Boom.unauthorized(null, options.tokenType));
            }

            const token = parts[1];

            settings.validateFunc.call(request, token, (err, isValid, credentials) => {

                if (err) {
                    return reply(err, { credentials: credentials, log: { tags: ['auth', 'bearer'], data: err } });
                }

                if (!isValid) {
                    return reply(Boom.unauthorized('Bad token', options.tokenType), { credentials: credentials });
                }

                if (!credentials
                    || typeof credentials !== 'object') {
                    return reply(Boom.badImplementation('Bad token string received for Bearer auth validation'), { log: { tags: 'token' } });
                }

                return reply.continue({ credentials: credentials });
            });
        }
    };

    return scheme;
};
<|endoftext|>


<commit_before>// Dependencies
var Gry = require("gry")
  , IsThere = require("is-there")
  , Ul = require("ul")
  , Tmp = require("tmp")
  , OArgv = require("oargv")
  , Path = require("path")
  , Glob = require("glob")
  , Logger = require("bug-killer")
  , OneByOne = require("one-by-one")
  , Mkdirp = require("mkdirp")
  , ReadJson = require("r-json")
  , WriteJson = require("w-json")
  , SameTime = require("same-time")
  , Ncp = require("ncp")
  ;

// Constants
const PATH_LIBS = "/ajax/libs/"
    , PATH_DIST = ["/dist", "/build", "/src", "/"]
    , PATH_PACK = "package.json"
    ;

/**
 * CdnJsImporter
 * Creates a new instance of `CdnJsImporter`.
 *
 * @name CdnJsImporter
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `libs` (Array): An array of `Lib` items (see the `add` method what they should contain). They will be downloaded in parallel (default: `[]`).
 *  - `debug` (Boolean|Number): A boolean or number value indicating the log level (default: `false`).
 *  - `cdnjs` (String): The absolute path to the local cdnjs repository.
 *
 * @param {Function} callback The callback function.
 * @return {CdnJsImporter} The `CdnJsImporter` instance.
 */
function CdnJsImporter (options, callback) {

    if (this.constructor !== CdnJsImporter) {
        return new CdnJsImporter(options, callback);
    }

    // Defaults
    options = Ul.merge(options, {
        libs: []
      , debug: false
    });
    callback = callback || function (err) {};

    // Debug mode
    Logger.config.level = options.debug === true
                           ? 4
                           : (typeof options.debug === "number"
                           ? options.debug : 0)
                           ;

    var self = this;

    // Check if the cdnjs exists
    self.root = options.cdnjs + PATH_LIBS;
    if (!IsThere(self.root)) {
        return callback(new Error("The cdnjs library directory doesn't exist."));
    }

    // Create a gry instance in the cdnjs repository
    self.git = new Gry(self.root);

    if (options.libs.length) {
        SameTime(options.libs.map(function (cLib) {
            return self.add.bind(self, cLib);
        }), callback);
    }
}

/**
 * add
 * Adds a new library in the local cdnjs repository.
 *
 * @name add
 * @function
 * @param {Object|String} lib The git url as string or an object containing:
 *  - `git` (String): The `git` url.
 *  - `dir` (String): The directory containing the files which should be imported (default: `"/dist"` or `"/build"` or `"/src"` or `"/"`).
 *  - `map` (Array): The file map used by cdnjs in autoupdate process (default: `[{ basePath: lib.dir , files: ["**\/*"] }]`).
 * @param {Function} callback The callback function called with `error` and `data`.
 * @return {CdnJsImporter} The `CdnJsImporter` instance.
 */
CdnJsImporter.prototype.add = function (lib, callback) {
    var self = this
      , pack = {}
      , i = 0
      , srcDir = ""
      , cDir = null
      , libPath = ""
      , vPath = ""
      , package = {}
      , path = ""
      , files = []
      ;

    // Handle strings
    if (typeof lib === "string") {
        lib = {
            git: lib
        };
    }

    lib = Ul.merge(lib, {
        dir: null
    });

    OneByOne([
        // Create tmp directory
        Tmp.dir.bind(Tmp)
        // Clone the library repo
      , function (cb, tmpPath) {
            path = tmpPath;
            Logger.log("Cloning " + lib.git + " into " + path, "info");
            self.repo = new Gry(path);
            self.repo_path = path;
            self.repo.exec(OArgv({
                _: [lib.git, "."]
            }, "clone"), function (err) {
                if (err) { return cb("Failed to clone the repository: " + err.toString()); }
                cb();
            });
        }
        // Read the package.json file
      , function (cb) {

            // Use the package.json
            pack = Path.join(self.repo_path, PATH_PACK);
            srcDir = path;

            // Check if the package.json file exists
            // TODO Import from NPM
            if (!IsThere(pack)) {
                return callback(new Error("package.json is required."));
            }

            // Detect the cdn files
            if (!lib.dir) {
                for (; i < PATH_DIST.length; ++i) {
                    cDir = path + PATH_DIST[i];
                    if (IsThere(cDir)) {
                        srcDir = cDir;
                        lib.dir = PATH_DIST[i]
                        break;
                    }
                }
            }

            Logger.log("Set the source path: " + lib.dir, "info");
            ReadJson(pack, function (err, pack) {
                if (err) { return callback(new Error("Failed to read the package.json file: " + err.toString())); }
                package = pack;
                cb();
            });
        }
        // Create the version directory
      , function (cb) {
            libPath = Path.join(self.root, package.name);
            vPath = Path.join(libPath, package.version);

            // Create the version directory
            Logger.log("Creating the version directory: " + vPath, "info");

            // Append the auto-update fields
            package.npmName = package.name;
            package.npmFileMap = lib.map || [
                {
                    basePath: lib.dir
                  , files: ["**/*"]
                }
            ];

            Mkdirp(vPath, cb);
        }
        // Fetch the needed files
      , function (cb) {
            // Get the library files
            Logger.log("Getting the library files.", "info");

            // TODO Handle the whole array
            var basePath = Path.join(path, package.npmFileMap[0].basePath, package.npmFileMap[0].files[0]);

            Glob(basePath, function (err, libFiles) {
                if (err) { return cb(new Error("Failed to get the library files: " + err.toString())); }
                files = libFiles;

                // Append the filename field used by cdnjs
                package.filename = files[0].replace(Path.join(self.repo.cwd, package.npmFileMap[0].basePath) + "/", "");
                cb();
            });
        }
        // Write the package.json file
      , function (cb) {
            // Create the package.json file in the cdnjs repository
            Logger.log("Writing the package.json file in " + libPath, "info");

            WriteJson(Path.join(libPath, PATH_PACK), package, function (err) {
                if (err) { return cb(new Error("Failed to create the package.json file: " + err.toString())); }
                cb();
            });
        }
        // Copy the library files
      , function (cb) {
            Logger.log("Copying the library files", "info");
            SameTime(files.map(function (cPath) {
                return Ncp.bind(this, cPath, Path.join(vPath, cPath.split("/").pop()));
            }), function (err) {
                if (err) {
                    Logger.log("Failed to copy the library files: " + err.toString(), "error");
                    return cb(err);
                }
                cb();
            });
        }
        // Checkout the master branch
      , function (cb) {
            Logger.log("Checking out the master branch.", "info");
            cb();
        }
      , self.git.exec.bind(self.git, "checkout master")
        // Pull from github/cdnjs/cdnjs
      , function (cb) {
            Logger.log("Pulling from origin.", "info");
            cb();
        }
      , self.git.exec.bind(self.git, "pull origin master")
        // Create the new branch
      , function (cb) {
            Logger.log("Creating a new branch for your library.", "info");
            self.git.exec(OArgv({
                _: "importer-" + package.name
              , b: true
            }, "checkout"), cb)
        }
        // Add files
      , function (cb) {
            Logger.log("Adding the new library files in the git repository.", "info");
            self.git.exec("add . -A", function (err) {
                if (err) {
                    Logger.log("Failed to add the files: " + err.toString(), "error");
                    return cb(err);
                }
                cb();
            });
        }
        // Commit the changes
      , function (cb) {
            Logger.log("Committing the changes", "info");
            var message = "Added " + package.name + "@" + package.version;
            self.git.commit(message, function (err) {
                if (err) {
                    Logger.log("Failed to commit the changes: " + err.toString(), "error");
                    return cb(err);
                }

                // Done
                Logger.log(message, "info");
                cb();
            });
        }
    ], callback);
};

module.exports = CdnJsImporter;
<commit_msg>Include the version name as well<commit_after>// Dependencies
var Gry = require("gry")
  , IsThere = require("is-there")
  , Ul = require("ul")
  , Tmp = require("tmp")
  , OArgv = require("oargv")
  , Path = require("path")
  , Glob = require("glob")
  , Logger = require("bug-killer")
  , OneByOne = require("one-by-one")
  , Mkdirp = require("mkdirp")
  , ReadJson = require("r-json")
  , WriteJson = require("w-json")
  , SameTime = require("same-time")
  , Ncp = require("ncp")
  ;

// Constants
const PATH_LIBS = "/ajax/libs/"
    , PATH_DIST = ["/dist", "/build", "/src", "/"]
    , PATH_PACK = "package.json"
    ;

/**
 * CdnJsImporter
 * Creates a new instance of `CdnJsImporter`.
 *
 * @name CdnJsImporter
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `libs` (Array): An array of `Lib` items (see the `add` method what they should contain). They will be downloaded in parallel (default: `[]`).
 *  - `debug` (Boolean|Number): A boolean or number value indicating the log level (default: `false`).
 *  - `cdnjs` (String): The absolute path to the local cdnjs repository.
 *
 * @param {Function} callback The callback function.
 * @return {CdnJsImporter} The `CdnJsImporter` instance.
 */
function CdnJsImporter (options, callback) {

    if (this.constructor !== CdnJsImporter) {
        return new CdnJsImporter(options, callback);
    }

    // Defaults
    options = Ul.merge(options, {
        libs: []
      , debug: false
    });
    callback = callback || function (err) {};

    // Debug mode
    Logger.config.level = options.debug === true
                           ? 4
                           : (typeof options.debug === "number"
                           ? options.debug : 0)
                           ;

    var self = this;

    // Check if the cdnjs exists
    self.root = options.cdnjs + PATH_LIBS;
    if (!IsThere(self.root)) {
        return callback(new Error("The cdnjs library directory doesn't exist."));
    }

    // Create a gry instance in the cdnjs repository
    self.git = new Gry(self.root);

    if (options.libs.length) {
        SameTime(options.libs.map(function (cLib) {
            return self.add.bind(self, cLib);
        }), callback);
    }
}

/**
 * add
 * Adds a new library in the local cdnjs repository.
 *
 * @name add
 * @function
 * @param {Object|String} lib The git url as string or an object containing:
 *  - `git` (String): The `git` url.
 *  - `dir` (String): The directory containing the files which should be imported (default: `"/dist"` or `"/build"` or `"/src"` or `"/"`).
 *  - `map` (Array): The file map used by cdnjs in autoupdate process (default: `[{ basePath: lib.dir , files: ["**\/*"] }]`).
 * @param {Function} callback The callback function called with `error` and `data`.
 * @return {CdnJsImporter} The `CdnJsImporter` instance.
 */
CdnJsImporter.prototype.add = function (lib, callback) {
    var self = this
      , pack = {}
      , i = 0
      , srcDir = ""
      , cDir = null
      , libPath = ""
      , vPath = ""
      , package = {}
      , path = ""
      , files = []
      ;

    // Handle strings
    if (typeof lib === "string") {
        lib = {
            git: lib
        };
    }

    lib = Ul.merge(lib, {
        dir: null
    });

    OneByOne([
        // Create tmp directory
        Tmp.dir.bind(Tmp)
        // Clone the library repo
      , function (cb, tmpPath) {
            path = tmpPath;
            Logger.log("Cloning " + lib.git + " into " + path, "info");
            self.repo = new Gry(path);
            self.repo_path = path;
            self.repo.exec(OArgv({
                _: [lib.git, "."]
            }, "clone"), function (err) {
                if (err) { return cb("Failed to clone the repository: " + err.toString()); }
                cb();
            });
        }
        // Read the package.json file
      , function (cb) {

            // Use the package.json
            pack = Path.join(self.repo_path, PATH_PACK);
            srcDir = path;

            // Check if the package.json file exists
            // TODO Import from NPM
            if (!IsThere(pack)) {
                return callback(new Error("package.json is required."));
            }

            // Detect the cdn files
            if (!lib.dir) {
                for (; i < PATH_DIST.length; ++i) {
                    cDir = path + PATH_DIST[i];
                    if (IsThere(cDir)) {
                        srcDir = cDir;
                        lib.dir = PATH_DIST[i]
                        break;
                    }
                }
            }

            Logger.log("Set the source path: " + lib.dir, "info");
            ReadJson(pack, function (err, pack) {
                if (err) { return callback(new Error("Failed to read the package.json file: " + err.toString())); }
                package = pack;
                cb();
            });
        }
        // Create the version directory
      , function (cb) {
            libPath = Path.join(self.root, package.name);
            vPath = Path.join(libPath, package.version);

            // Create the version directory
            Logger.log("Creating the version directory: " + vPath, "info");

            // Append the auto-update fields
            package.npmName = package.name;
            package.npmFileMap = lib.map || [
                {
                    basePath: lib.dir
                  , files: ["**/*"]
                }
            ];

            Mkdirp(vPath, cb);
        }
        // Fetch the needed files
      , function (cb) {
            // Get the library files
            Logger.log("Getting the library files.", "info");

            // TODO Handle the whole array
            var basePath = Path.join(path, package.npmFileMap[0].basePath, package.npmFileMap[0].files[0]);

            Glob(basePath, function (err, libFiles) {
                if (err) { return cb(new Error("Failed to get the library files: " + err.toString())); }
                files = libFiles;

                // Append the filename field used by cdnjs
                package.filename = files[0].replace(Path.join(self.repo.cwd, package.npmFileMap[0].basePath) + "/", "");
                cb();
            });
        }
        // Write the package.json file
      , function (cb) {
            // Create the package.json file in the cdnjs repository
            Logger.log("Writing the package.json file in " + libPath, "info");

            WriteJson(Path.join(libPath, PATH_PACK), package, function (err) {
                if (err) { return cb(new Error("Failed to create the package.json file: " + err.toString())); }
                cb();
            });
        }
        // Copy the library files
      , function (cb) {
            Logger.log("Copying the library files", "info");
            SameTime(files.map(function (cPath) {
                return Ncp.bind(this, cPath, Path.join(vPath, cPath.split("/").pop()));
            }), function (err) {
                if (err) {
                    Logger.log("Failed to copy the library files: " + err.toString(), "error");
                    return cb(err);
                }
                cb();
            });
        }
        // Checkout the master branch
      , function (cb) {
            Logger.log("Checking out the master branch.", "info");
            cb();
        }
      , self.git.exec.bind(self.git, "checkout master")
        // Pull from github/cdnjs/cdnjs
      , function (cb) {
            Logger.log("Pulling from origin.", "info");
            cb();
        }
      , self.git.exec.bind(self.git, "pull origin master")
        // Create the new branch
      , function (cb) {
            Logger.log("Creating a new branch for your library.", "info");
            self.git.exec(OArgv({
                _: "importer-" + package.name + "@" + package.version
              , b: true
            }, "checkout"), cb)
        }
        // Add files
      , function (cb) {
            Logger.log("Adding the new library files in the git repository.", "info");
            self.git.exec("add . -A", function (err) {
                if (err) {
                    Logger.log("Failed to add the files: " + err.toString(), "error");
                    return cb(err);
                }
                cb();
            });
        }
        // Commit the changes
      , function (cb) {
            Logger.log("Committing the changes", "info");
            var message = "Added " + package.name + "@" + package.version;
            self.git.commit(message, function (err) {
                if (err) {
                    Logger.log("Failed to commit the changes: " + err.toString(), "error");
                    return cb(err);
                }

                // Done
                Logger.log(message, "info");
                cb();
            });
        }
    ], callback);
};

module.exports = CdnJsImporter;
<|endoftext|>


<commit_before>(function () {
// Constants
var SEP = "/"
    , DYN = ":"
    ;

/**
 * Ruut
 * Creates a new router.
 *
 * @name Ruut
 * @function
 * @param {Array|Object} routes An array or an object representing routes: If
 * it's an array, then the format is:
 *
 *  - `0` (Function|Non-null-values): If function, then it will be called and
 *    the data will be the returned value, otherwise the non-`null` value.
 *  - `1` (Array|Object): A route object/array (recursive definition).
 *  - `2` (Function|Non-null-values): This value/function is returned/called
 *    when no other routes were found.
 *
 * If the `routes` value is an object it should be in the following format:
 *
 * ```js
 * {
 *     // /some
 *     "some": {
 *         // /some/route
 *         "route": {
 *             // /some/route/with
 *             "with": {
 *                 // /some/route/with/anything-you-want
 *                 ":dynamic": {
 *                     // /some/route/with/anything-you-want/value
 *                     "value": function (params) {
 *                         return "This can be a function or a non-null value. The dynamic value is: " + params.dynamic;
 *                     }
 *                 }
 *             }
 *         }
 *     }
 * }
 * ```
 *
 * @return {Function} The `check` function getting the pathname as argument.
 */
function Ruut(routes) {
    routes = routes || {};
    return Ruut.check.bind(this, routes);
}

/**
 * search
 * Searches the pathname in the routes object, recursively. This is used internally.
 *
 * @name check
 * @function
 * @param {Routes} routes The routes to check the pathname in.
 * @param {String} pathname The pathname.
 * @return {Object} An object containing:
 *
 *  - `is_valid` (Boolean): `true` if the route was foud, `false` otherwise.
 *  - `_` (Function|Non-null-value): The route data.
 *  - `params` (Object): The dynamic parameters.
 */
Ruut.search = function (routes, pathname, params) {

    if (!Array.isArray(routes)) {
        routes = [null, routes, null];
    }

    if (pathname === SEP) {
        if (routes[0] === null) {
            return {
                is_valid: false
            };
        }
        return {
            is_valid: true
          , _: routes[0]
          , params: params
        };
    }

    if (pathname.charAt(0) === SEP) {
        pathname = pathname.substr(1);
    }

    var nextIndex = pathname.indexOf(SEP)
      , cSplit = nextIndex !== -1 ? pathname.substr(0, nextIndex) : pathname
      , found = routes[1][cSplit]
      , dynamicField = null
      ;

    if (typeof found === "object") {
        if (nextIndex === -1) {
            return Ruut.search(found, SEP, params);
        }
        return Ruut.search(found, pathname.substr(nextIndex), params);
    }

    if (found !== undefined) {
        return {
            is_valid: true
          , _: found
          , params: params
        };
    }

    dynamicField = Object.keys(routes[1]).filter(function (c) {
        return c.charAt(0) === DYN;
    })[0];

    if (dynamicField) {
        found = routes[1][dynamicField];
        params[dynamicField.substr(1)] = cSplit;
        if (typeof found === "object") {
            nextIndex = pathname.indexOf(SEP);
            if (nextIndex === -1) {
                return Ruut.search(found, SEP, params);
            }
            return Ruut.search(found, pathname.substr(nextIndex), params);
        }
        return {
            is_valid: true
          , _: found
          , params: params
        };
    }

    if (routes[2]) {
        return {
            is_valid: true
          , _: routes[2]
          , params: params
        };
    }

    return {
        is_valid: false
    }
};

/**
 * check
 * Searches the pathname in the routes object and prepares the final object. This is used internally.
 *
 * @name check
 * @function
 * @param {Routes} routes The routes to check the pathname in.
 * @param {String} pathname The pathname.
 * @return {Object|null} The found route containing `data` and `params` fields or `null` otherwise.
 */
Ruut.check = function (routes, pathname) {
    var found = Ruut.search(routes, pathname, {});
    if (found.is_valid) {
        if (typeof found._ === "function") {
            return {
                data: found._(found.params)
              , params: found.params
            };
        }
        return {
            data: found._
          , params: found.params
        };
    }
    return null;
};

if (typeof module === "object") {
    module.exports = Ruut;
} else if (typeof window === "object") {
    window.Ruut = Ruut;
}

})();
<commit_msg>Syntax<commit_after>(function () {
// Constants
var SEP = "/"
  , DYN = ":"
  ;

/**
 * Ruut
 * Creates a new router.
 *
 * @name Ruut
 * @function
 * @param {Array|Object} routes An array or an object representing routes: If
 * it's an array, then the format is:
 *
 *  - `0` (Function|Non-null-values): If function, then it will be called and
 *    the data will be the returned value, otherwise the non-`null` value.
 *  - `1` (Array|Object): A route object/array (recursive definition).
 *  - `2` (Function|Non-null-values): This value/function is returned/called
 *    when no other routes were found.
 *
 * If the `routes` value is an object it should be in the following format:
 *
 * ```js
 * {
 *     // /some
 *     "some": {
 *         // /some/route
 *         "route": {
 *             // /some/route/with
 *             "with": {
 *                 // /some/route/with/anything-you-want
 *                 ":dynamic": {
 *                     // /some/route/with/anything-you-want/value
 *                     "value": function (params) {
 *                         return "This can be a function or a non-null value. The dynamic value is: " + params.dynamic;
 *                     }
 *                 }
 *             }
 *         }
 *     }
 * }
 * ```
 *
 * @return {Function} The `check` function getting the pathname as argument.
 */
function Ruut(routes) {
    routes = routes || {};
    return Ruut.check.bind(this, routes);
}

/**
 * search
 * Searches the pathname in the routes object, recursively. This is used internally.
 *
 * @name check
 * @function
 * @param {Routes} routes The routes to check the pathname in.
 * @param {String} pathname The pathname.
 * @return {Object} An object containing:
 *
 *  - `is_valid` (Boolean): `true` if the route was foud, `false` otherwise.
 *  - `_` (Function|Non-null-value): The route data.
 *  - `params` (Object): The dynamic parameters.
 */
Ruut.search = function (routes, pathname, params) {

    if (!Array.isArray(routes)) {
        routes = [null, routes, null];
    }

    if (pathname === SEP) {
        if (routes[0] === null) {
            return {
                is_valid: false
            };
        }
        return {
            is_valid: true
          , _: routes[0]
          , params: params
        };
    }

    if (pathname.charAt(0) === SEP) {
        pathname = pathname.substr(1);
    }

    var nextIndex = pathname.indexOf(SEP)
      , cSplit = nextIndex !== -1 ? pathname.substr(0, nextIndex) : pathname
      , found = routes[1][cSplit]
      , dynamicField = null
      ;

    if (typeof found === "object") {
        if (nextIndex === -1) {
            return Ruut.search(found, SEP, params);
        }
        return Ruut.search(found, pathname.substr(nextIndex), params);
    }

    if (found !== undefined) {
        return {
            is_valid: true
          , _: found
          , params: params
        };
    }

    dynamicField = Object.keys(routes[1]).filter(function (c) {
        return c.charAt(0) === DYN;
    })[0];

    if (dynamicField) {
        found = routes[1][dynamicField];
        params[dynamicField.substr(1)] = cSplit;
        if (typeof found === "object") {
            nextIndex = pathname.indexOf(SEP);
            if (nextIndex === -1) {
                return Ruut.search(found, SEP, params);
            }
            return Ruut.search(found, pathname.substr(nextIndex), params);
        }
        return {
            is_valid: true
          , _: found
          , params: params
        };
    }

    if (routes[2]) {
        return {
            is_valid: true
          , _: routes[2]
          , params: params
        };
    }

    return {
        is_valid: false
    }
};

/**
 * check
 * Searches the pathname in the routes object and prepares the final object. This is used internally.
 *
 * @name check
 * @function
 * @param {Routes} routes The routes to check the pathname in.
 * @param {String} pathname The pathname.
 * @return {Object|null} The found route containing `data` and `params` fields or `null` otherwise.
 */
Ruut.check = function (routes, pathname) {
    var found = Ruut.search(routes, pathname, {});
    if (found.is_valid) {
        if (typeof found._ === "function") {
            return {
                data: found._(found.params)
              , params: found.params
            };
        }
        return {
            data: found._
          , params: found.params
        };
    }
    return null;
};

if (typeof module === "object") {
    module.exports = Ruut;
} else if (typeof window === "object") {
    window.Ruut = Ruut;
}

})();
<|endoftext|>