1 | 'use strict';
|
---|
2 | /*
|
---|
3 | Copyright 2012-2015, Yahoo Inc.
|
---|
4 | Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
|
---|
5 | */
|
---|
6 | const path = require('path');
|
---|
7 | const fs = require('fs');
|
---|
8 | const mkdirp = require('make-dir');
|
---|
9 | const supportsColor = require('supports-color');
|
---|
10 |
|
---|
11 | /**
|
---|
12 | * Base class for writing content
|
---|
13 | * @class ContentWriter
|
---|
14 | * @constructor
|
---|
15 | */
|
---|
16 | class ContentWriter {
|
---|
17 | /**
|
---|
18 | * returns the colorized version of a string. Typically,
|
---|
19 | * content writers that write to files will return the
|
---|
20 | * same string and ones writing to a tty will wrap it in
|
---|
21 | * appropriate escape sequences.
|
---|
22 | * @param {String} str the string to colorize
|
---|
23 | * @param {String} clazz one of `high`, `medium` or `low`
|
---|
24 | * @returns {String} the colorized form of the string
|
---|
25 | */
|
---|
26 | colorize(str /*, clazz*/) {
|
---|
27 | return str;
|
---|
28 | }
|
---|
29 |
|
---|
30 | /**
|
---|
31 | * writes a string appended with a newline to the destination
|
---|
32 | * @param {String} str the string to write
|
---|
33 | */
|
---|
34 | println(str) {
|
---|
35 | this.write(`${str}\n`);
|
---|
36 | }
|
---|
37 |
|
---|
38 | /**
|
---|
39 | * closes this content writer. Should be called after all writes are complete.
|
---|
40 | */
|
---|
41 | close() {}
|
---|
42 | }
|
---|
43 |
|
---|
44 | /**
|
---|
45 | * a content writer that writes to a file
|
---|
46 | * @param {Number} fd - the file descriptor
|
---|
47 | * @extends ContentWriter
|
---|
48 | * @constructor
|
---|
49 | */
|
---|
50 | class FileContentWriter extends ContentWriter {
|
---|
51 | constructor(fd) {
|
---|
52 | super();
|
---|
53 |
|
---|
54 | this.fd = fd;
|
---|
55 | }
|
---|
56 |
|
---|
57 | write(str) {
|
---|
58 | fs.writeSync(this.fd, str);
|
---|
59 | }
|
---|
60 |
|
---|
61 | close() {
|
---|
62 | fs.closeSync(this.fd);
|
---|
63 | }
|
---|
64 | }
|
---|
65 |
|
---|
66 | // allow stdout to be captured for tests.
|
---|
67 | let capture = false;
|
---|
68 | let output = '';
|
---|
69 |
|
---|
70 | /**
|
---|
71 | * a content writer that writes to the console
|
---|
72 | * @extends ContentWriter
|
---|
73 | * @constructor
|
---|
74 | */
|
---|
75 | class ConsoleWriter extends ContentWriter {
|
---|
76 | write(str) {
|
---|
77 | if (capture) {
|
---|
78 | output += str;
|
---|
79 | } else {
|
---|
80 | process.stdout.write(str);
|
---|
81 | }
|
---|
82 | }
|
---|
83 |
|
---|
84 | colorize(str, clazz) {
|
---|
85 | const colors = {
|
---|
86 | low: '31;1',
|
---|
87 | medium: '33;1',
|
---|
88 | high: '32;1'
|
---|
89 | };
|
---|
90 |
|
---|
91 | /* istanbul ignore next: different modes for CI and local */
|
---|
92 | if (supportsColor.stdout && colors[clazz]) {
|
---|
93 | return `\u001b[${colors[clazz]}m${str}\u001b[0m`;
|
---|
94 | }
|
---|
95 | return str;
|
---|
96 | }
|
---|
97 | }
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * utility for writing files under a specific directory
|
---|
101 | * @class FileWriter
|
---|
102 | * @param {String} baseDir the base directory under which files should be written
|
---|
103 | * @constructor
|
---|
104 | */
|
---|
105 | class FileWriter {
|
---|
106 | constructor(baseDir) {
|
---|
107 | if (!baseDir) {
|
---|
108 | throw new Error('baseDir must be specified');
|
---|
109 | }
|
---|
110 | this.baseDir = baseDir;
|
---|
111 | }
|
---|
112 |
|
---|
113 | /**
|
---|
114 | * static helpers for capturing stdout report output;
|
---|
115 | * super useful for tests!
|
---|
116 | */
|
---|
117 | static startCapture() {
|
---|
118 | capture = true;
|
---|
119 | }
|
---|
120 |
|
---|
121 | static stopCapture() {
|
---|
122 | capture = false;
|
---|
123 | }
|
---|
124 |
|
---|
125 | static getOutput() {
|
---|
126 | return output;
|
---|
127 | }
|
---|
128 |
|
---|
129 | static resetOutput() {
|
---|
130 | output = '';
|
---|
131 | }
|
---|
132 |
|
---|
133 | /**
|
---|
134 | * returns a FileWriter that is rooted at the supplied subdirectory
|
---|
135 | * @param {String} subdir the subdirectory under which to root the
|
---|
136 | * returned FileWriter
|
---|
137 | * @returns {FileWriter}
|
---|
138 | */
|
---|
139 | writerForDir(subdir) {
|
---|
140 | if (path.isAbsolute(subdir)) {
|
---|
141 | throw new Error(
|
---|
142 | `Cannot create subdir writer for absolute path: ${subdir}`
|
---|
143 | );
|
---|
144 | }
|
---|
145 | return new FileWriter(`${this.baseDir}/${subdir}`);
|
---|
146 | }
|
---|
147 |
|
---|
148 | /**
|
---|
149 | * copies a file from a source directory to a destination name
|
---|
150 | * @param {String} source path to source file
|
---|
151 | * @param {String} dest relative path to destination file
|
---|
152 | * @param {String} [header=undefined] optional text to prepend to destination
|
---|
153 | * (e.g., an "this file is autogenerated" comment, copyright notice, etc.)
|
---|
154 | */
|
---|
155 | copyFile(source, dest, header) {
|
---|
156 | if (path.isAbsolute(dest)) {
|
---|
157 | throw new Error(`Cannot write to absolute path: ${dest}`);
|
---|
158 | }
|
---|
159 | dest = path.resolve(this.baseDir, dest);
|
---|
160 | mkdirp.sync(path.dirname(dest));
|
---|
161 | let contents;
|
---|
162 | if (header) {
|
---|
163 | contents = header + fs.readFileSync(source, 'utf8');
|
---|
164 | } else {
|
---|
165 | contents = fs.readFileSync(source);
|
---|
166 | }
|
---|
167 | fs.writeFileSync(dest, contents);
|
---|
168 | }
|
---|
169 |
|
---|
170 | /**
|
---|
171 | * returns a content writer for writing content to the supplied file.
|
---|
172 | * @param {String|null} file the relative path to the file or the special
|
---|
173 | * values `"-"` or `null` for writing to the console
|
---|
174 | * @returns {ContentWriter}
|
---|
175 | */
|
---|
176 | writeFile(file) {
|
---|
177 | if (file === null || file === '-') {
|
---|
178 | return new ConsoleWriter();
|
---|
179 | }
|
---|
180 | if (path.isAbsolute(file)) {
|
---|
181 | throw new Error(`Cannot write to absolute path: ${file}`);
|
---|
182 | }
|
---|
183 | file = path.resolve(this.baseDir, file);
|
---|
184 | mkdirp.sync(path.dirname(file));
|
---|
185 | return new FileContentWriter(fs.openSync(file, 'w'));
|
---|
186 | }
|
---|
187 | }
|
---|
188 |
|
---|
189 | module.exports = FileWriter;
|
---|