| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 | /* * grunt * http://gruntjs.com/ * * Copyright (c) 2014 "Cowboy" Ben Alman * Licensed under the MIT license. * https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT */'use strict';// Nodejs libs.var util = require('util');// External libs.var hooker = require('hooker');// Requiring this here modifies the String prototype!var colors = require('colors');// The upcoming lodash 2.5+ should remove the need for underscore.string.var _ = require('lodash');_.str = require('underscore.string');_.mixin(_.str.exports());// TODO: ADD CHALKvar logUtils = require('grunt-legacy-log-utils');function Log(options) {  // This property always refers to the "base" logger.  this.always = this;  // Extend options.  this.options = _.extend({}, {    // Show colors in output?    color: true,    // Enable verbose-mode logging?    verbose: false,    // Enable debug logging statement?    debug: false,    // Where should messages be output?    outStream: process.stdout,    // NOTE: the color, verbose, debug options will be ignored if the    // "grunt" option is specified! See the Log.prototype.option and    // the Log.prototype.error methods for more info.    grunt: null,    // Where should output wrap? If null, use legacy Grunt defaults.    maxCols: null,    // Should logger start muted?    muted: false,  }, options);  // True once anything has actually been logged.  this.hasLogged = false;  // Related verbose / notverbose loggers.  this.verbose = new VerboseLog(this, true);  this.notverbose = new VerboseLog(this, false);  this.verbose.or = this.notverbose;  this.notverbose.or = this.verbose;  // Apparently, people have using grunt.log in interesting ways. Just bind  // all methods so that "this" is irrelevant.  if (this.options.grunt) {    _.bindAll(this);    _.bindAll(this.verbose);    _.bindAll(this.notverbose);  }}exports.Log = Log;// Am I doing it wrong? :Pfunction VerboseLog(parentLog, verbose) {  // Keep track of the original, base "Log" instance.  this.always = parentLog;  // This logger is either verbose (true) or notverbose (false).  this._isVerbose = verbose;}util.inherits(VerboseLog, Log);VerboseLog.prototype._write = function() {  // Abort if not in correct verbose mode.  if (Boolean(this.option('verbose')) !== this._isVerbose) { return; }  // Otherwise... log!  return VerboseLog.super_.prototype._write.apply(this, arguments);};// Create read/write accessors that prefer the parent log's properties (in// the case of verbose/notverbose) to the current log's properties.function makeSmartAccessor(name, isOption) {  Object.defineProperty(Log.prototype, name, {    enumerable: true,    configurable: true,    get: function() {      return isOption ? this.always._options[name] : this.always['_' + name];    },    set: function(value) {      if (isOption) {        this.always._options[name] = value;      } else {        this.always['_' + name] = value;      }    },  });}makeSmartAccessor('options');makeSmartAccessor('hasLogged');makeSmartAccessor('muted', true);// Disable colors if --no-colors was passed.Log.prototype.initColors = function() {  if (this.option('no-color')) {    // String color getters should just return the string.    colors.mode = 'none';    // Strip colors from strings passed to console.log.    hooker.hook(console, 'log', function() {      var args = _.toArray(arguments);      return hooker.filter(this, args.map(function(arg) {        return typeof arg === 'string' ? colors.stripColors(arg) : arg;      }));    });  }};// Check for color, verbose, debug options through Grunt if specified,// otherwise defer to options object properties.Log.prototype.option = function(name) {  if (this.options.grunt && this.options.grunt.option) {    return this.options.grunt.option(name);  }  var no = name.match(/^no-(.+)$/);  return no ? !this.options[no[1]] : this.options[name];};// Parse certain markup in strings to be logged.Log.prototype._markup = function(str) {  str = str || '';  // Make _foo_ underline.  str = str.replace(/(\s|^)_(\S|\S[\s\S]+?\S)_(?=[\s,.!?]|$)/g, '$1' + '$2'.underline);  // Make *foo* bold.  str = str.replace(/(\s|^)\*(\S|\S[\s\S]+?\S)\*(?=[\s,.!?]|$)/g, '$1' + '$2'.bold);  return str;};// Similar to util.format in the standard library, however it'll always// convert the first argument to a string and treat it as the format string.Log.prototype._format = function(args) {  args = _.toArray(args);  if (args.length > 0) {    args[0] = String(args[0]);  }  return util.format.apply(util, args);};Log.prototype._write = function(msg) {  // Abort if muted.  if (this.muted) { return; }  // Actually write output.  this.hasLogged = true;  msg = msg || '';  // Users should probably use the colors-provided methods, but if they  // don't, this should strip extraneous color codes.  if (this.option('no-color')) { msg = colors.stripColors(msg); }  // Actually write to stdout.  this.options.outStream.write(this._markup(msg));};Log.prototype._writeln = function(msg) {  // Write blank line if no msg is passed in.  this._write((msg || '') + '\n');};// Write output.Log.prototype.write = function() {  this._write(this._format(arguments));  return this;};// Write a line of output.Log.prototype.writeln = function() {  this._writeln(this._format(arguments));  return this;};Log.prototype.warn = function() {  var msg = this._format(arguments);  if (arguments.length > 0) {    this._writeln('>> '.red + _.trim(msg).replace(/\n/g, '\n>> '.red));  } else {    this._writeln('ERROR'.red);  }  return this;};Log.prototype.error = function() {  if (this.options.grunt && this.options.grunt.fail) {    this.options.grunt.fail.errorcount++;  }  this.warn.apply(this, arguments);  return this;};Log.prototype.ok = function() {  var msg = this._format(arguments);  if (arguments.length > 0) {    this._writeln('>> '.green + _.trim(msg).replace(/\n/g, '\n>> '.green));  } else {    this._writeln('OK'.green);  }  return this;};Log.prototype.errorlns = function() {  var msg = this._format(arguments);  this.error(this.wraptext(this.options.maxCols || 77, msg));  return this;};Log.prototype.oklns = function() {  var msg = this._format(arguments);  this.ok(this.wraptext(this.options.maxCols || 77, msg));  return this;};Log.prototype.success = function() {  var msg = this._format(arguments);  this._writeln(msg.green);  return this;};Log.prototype.fail = function() {  var msg = this._format(arguments);  this._writeln(msg.red);  return this;};Log.prototype.header = function() {  var msg = this._format(arguments);  // Skip line before header, but not if header is the very first line output.  if (this.hasLogged) { this._writeln(); }  this._writeln(msg.underline);  return this;};Log.prototype.subhead = function() {  var msg = this._format(arguments);  // Skip line before subhead, but not if subhead is the very first line output.  if (this.hasLogged) { this._writeln(); }  this._writeln(msg.bold);  return this;};// For debugging.Log.prototype.debug = function() {  var msg = this._format(arguments);  if (this.option('debug')) {    this._writeln('[D] ' + msg.magenta);  }  return this;};// Write a line of a table.Log.prototype.writetableln = function(widths, texts) {  this._writeln(this.table(widths, texts));  return this;};// Wrap a long line of text.Log.prototype.writelns = function() {  var msg = this._format(arguments);  this._writeln(this.wraptext(this.options.maxCols || 80, msg));  return this;};// Display flags in verbose mode.Log.prototype.writeflags = function(obj, prefix) {  var wordlist;  if (Array.isArray(obj)) {    wordlist = this.wordlist(obj);  } else if (typeof obj === 'object' && obj) {    wordlist = this.wordlist(Object.keys(obj).map(function(key) {      var val = obj[key];      return key + (val === true ? '' : '=' + JSON.stringify(val));    }));  }  this._writeln((prefix || 'Flags') + ': ' + (wordlist || '(none)'.cyan));  return this;};// Add static methods.[  'wordlist',  'uncolor',  'wraptext',  'table',].forEach(function(prop) {  Log.prototype[prop] = exports[prop] = logUtils[prop];});
 |