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; |