195 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  Copyright 2012-2015, Yahoo Inc.
 | |
|  Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 | |
|  */
 | |
| const util = require('util');
 | |
| const path = require('path');
 | |
| const fs = require('fs');
 | |
| const mkdirp = require('make-dir');
 | |
| const supportsColor = require('supports-color');
 | |
| const isAbsolute =
 | |
|     path.isAbsolute ||
 | |
|     /* istanbul ignore next */ function(p) {
 | |
|         return path.resolve(p) === path.normalize(p);
 | |
|     };
 | |
| 
 | |
| /**
 | |
|  * abstract interface for writing content
 | |
|  * @class ContentWriter
 | |
|  * @constructor
 | |
|  */
 | |
| /* istanbul ignore next: abstract class */
 | |
| function ContentWriter() {}
 | |
| 
 | |
| /**
 | |
|  * writes a string as-is to the destination
 | |
|  * @param {String} str the string to write
 | |
|  */
 | |
| /* istanbul ignore next: abstract class */
 | |
| ContentWriter.prototype.write = function() {
 | |
|     throw new Error('write: must be overridden');
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * returns the colorized version of a string. Typically,
 | |
|  * content writers that write to files will return the
 | |
|  * same string and ones writing to a tty will wrap it in
 | |
|  * appropriate escape sequences.
 | |
|  * @param {String} str the string to colorize
 | |
|  * @param {String} clazz one of `high`, `medium` or `low`
 | |
|  * @returns {String} the colorized form of the string
 | |
|  */
 | |
| ContentWriter.prototype.colorize = function(str /*, clazz*/) {
 | |
|     return str;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * writes a string appended with a newline to the destination
 | |
|  * @param {String} str the string to write
 | |
|  */
 | |
| ContentWriter.prototype.println = function(str) {
 | |
|     this.write(str + '\n');
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * closes this content writer. Should be called after all writes are complete.
 | |
|  */
 | |
| ContentWriter.prototype.close = function() {};
 | |
| 
 | |
| /**
 | |
|  * a content writer that writes to a file
 | |
|  * @param {Number} fd - the file descriptor
 | |
|  * @extends ContentWriter
 | |
|  * @constructor
 | |
|  */
 | |
| function FileContentWriter(fd) {
 | |
|     this.fd = fd;
 | |
| }
 | |
| util.inherits(FileContentWriter, ContentWriter);
 | |
| 
 | |
| FileContentWriter.prototype.write = function(str) {
 | |
|     fs.writeSync(this.fd, str);
 | |
| };
 | |
| 
 | |
| FileContentWriter.prototype.close = function() {
 | |
|     fs.closeSync(this.fd);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * a content writer that writes to the console
 | |
|  * @extends ContentWriter
 | |
|  * @constructor
 | |
|  */
 | |
| function ConsoleWriter() {}
 | |
| util.inherits(ConsoleWriter, ContentWriter);
 | |
| 
 | |
| // allow stdout to be captured for tests.
 | |
| let capture = false;
 | |
| let output = '';
 | |
| ConsoleWriter.prototype.write = function(str) {
 | |
|     if (capture) {
 | |
|         output += str;
 | |
|     } else {
 | |
|         process.stdout.write(str);
 | |
|     }
 | |
| };
 | |
| 
 | |
| ConsoleWriter.prototype.colorize = function(str, clazz) {
 | |
|     const colors = {
 | |
|         low: '31;1',
 | |
|         medium: '33;1',
 | |
|         high: '32;1'
 | |
|     };
 | |
| 
 | |
|     /* istanbul ignore next: different modes for CI and local */
 | |
|     if (supportsColor.stdout && colors[clazz]) {
 | |
|         return '\u001b[' + colors[clazz] + 'm' + str + '\u001b[0m';
 | |
|     }
 | |
|     return str;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * utility for writing files under a specific directory
 | |
|  * @class FileWriter
 | |
|  * @param {String} baseDir the base directory under which files should be written
 | |
|  * @constructor
 | |
|  */
 | |
| function FileWriter(baseDir) {
 | |
|     if (!baseDir) {
 | |
|         throw new Error('baseDir must be specified');
 | |
|     }
 | |
|     this.baseDir = baseDir;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * static helpers for capturing stdout report output;
 | |
|  * super useful for tests!
 | |
|  */
 | |
| FileWriter.startCapture = function() {
 | |
|     capture = true;
 | |
| };
 | |
| FileWriter.stopCapture = function() {
 | |
|     capture = false;
 | |
| };
 | |
| FileWriter.getOutput = function() {
 | |
|     return output;
 | |
| };
 | |
| FileWriter.resetOutput = function() {
 | |
|     output = '';
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * returns a FileWriter that is rooted at the supplied subdirectory
 | |
|  * @param {String} subdir the subdirectory under which to root the
 | |
|  *  returned FileWriter
 | |
|  * @returns {FileWriter}
 | |
|  */
 | |
| FileWriter.prototype.writerForDir = function(subdir) {
 | |
|     if (isAbsolute(subdir)) {
 | |
|         throw new Error(
 | |
|             'Cannot create subdir writer for absolute path: ' + subdir
 | |
|         );
 | |
|     }
 | |
|     return new FileWriter(this.baseDir + '/' + subdir);
 | |
| };
 | |
| /**
 | |
|  * copies a file from a source directory to a destination name
 | |
|  * @param {String} source path to source file
 | |
|  * @param {String} dest relative path to destination file
 | |
|  * @param {String} [header=undefined] optional text to prepend to destination
 | |
|  *  (e.g., an "this file is autogenerated" comment, copyright notice, etc.)
 | |
|  */
 | |
| FileWriter.prototype.copyFile = function(source, dest, header) {
 | |
|     if (isAbsolute(dest)) {
 | |
|         throw new Error('Cannot write to absolute path: ' + dest);
 | |
|     }
 | |
|     dest = path.resolve(this.baseDir, dest);
 | |
|     mkdirp.sync(path.dirname(dest));
 | |
|     let contents;
 | |
|     if (header) {
 | |
|         contents = header + fs.readFileSync(source, 'utf8');
 | |
|     } else {
 | |
|         contents = fs.readFileSync(source);
 | |
|     }
 | |
|     fs.writeFileSync(dest, contents);
 | |
| };
 | |
| /**
 | |
|  * returns a content writer for writing content to the supplied file.
 | |
|  * @param {String|null} file the relative path to the file or the special
 | |
|  *  values `"-"` or `null` for writing to the console
 | |
|  * @returns {ContentWriter}
 | |
|  */
 | |
| FileWriter.prototype.writeFile = function(file) {
 | |
|     if (file === null || file === '-') {
 | |
|         return new ConsoleWriter();
 | |
|     }
 | |
|     if (isAbsolute(file)) {
 | |
|         throw new Error('Cannot write to absolute path: ' + file);
 | |
|     }
 | |
|     file = path.resolve(this.baseDir, file);
 | |
|     mkdirp.sync(path.dirname(file));
 | |
|     return new FileContentWriter(fs.openSync(file, 'w'));
 | |
| };
 | |
| 
 | |
| module.exports = FileWriter;
 |