UNPKG

8.94 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * strict-local
8 * @format
9 */
10'use strict';
11
12var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator");
13
14var _toConsumableArray2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/toConsumableArray"));
15
16/**
17 * CodegenDirectory is a helper class for scripts that generate code into one
18 * output directory. The purpose is to make it easy to only write files that
19 * have changed and delete files that are no longer generated.
20 * It gives statistics about added/removed/updated/unchanged in the end.
21 * The class also has an option to "validate" which means that no file
22 * operations are performed and only the statistics are created for what would
23 * have happened. If there's anything but "unchanged", someone probably forgot
24 * to run the codegen script.
25 *
26 * Example:
27 *
28 * const dir = new CodegenDirectory('/some/path/generated', {filesystem: require('fs')});
29 * // write files in case content changed (less watchman/mtime changes)
30 * dir.writeFile('OneFile.js', contents);
31 * dir.writeFile('OtherFile.js', contents);
32 *
33 * // delete files that are not generated
34 * dir.deleteExtraFiles();
35 *
36 * // arrays of file names to print or whatever
37 * dir.changes.created
38 * dir.changes.updated
39 * dir.changes.deleted
40 * dir.changes.unchanged
41 */
42var CodegenDirectory =
43/*#__PURE__*/
44function () {
45 function CodegenDirectory(dir, _ref) {
46 var _this = this;
47
48 var filesystem = _ref.filesystem,
49 onlyValidate = _ref.onlyValidate;
50 this._filesystem = filesystem || require("fs");
51 this.onlyValidate = onlyValidate;
52
53 if (this._filesystem.existsSync(dir)) {
54 !this._filesystem.statSync(dir).isDirectory() ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'Expected `%s` to be a directory.', dir) : require("fbjs/lib/invariant")(false) : void 0;
55 } else if (!this.onlyValidate) {
56 var dirs = [dir];
57
58 var parent = require("path").dirname(dir);
59
60 while (!this._filesystem.existsSync(parent)) {
61 dirs.unshift(parent);
62 parent = require("path").dirname(parent);
63 }
64
65 dirs.forEach(function (d) {
66 return _this._filesystem.mkdirSync(d);
67 });
68 }
69
70 this._files = new Set();
71 this.changes = {
72 deleted: [],
73 updated: [],
74 created: [],
75 unchanged: []
76 };
77 this._dir = dir;
78 }
79
80 CodegenDirectory.combineChanges = function combineChanges(dirs) {
81 var changes = {
82 deleted: [],
83 updated: [],
84 created: [],
85 unchanged: []
86 };
87 dirs.forEach(function (dir) {
88 var _changes$deleted, _changes$updated, _changes$created, _changes$unchanged;
89
90 (_changes$deleted = changes.deleted).push.apply(_changes$deleted, (0, _toConsumableArray2["default"])(dir.changes.deleted));
91
92 (_changes$updated = changes.updated).push.apply(_changes$updated, (0, _toConsumableArray2["default"])(dir.changes.updated));
93
94 (_changes$created = changes.created).push.apply(_changes$created, (0, _toConsumableArray2["default"])(dir.changes.created));
95
96 (_changes$unchanged = changes.unchanged).push.apply(_changes$unchanged, (0, _toConsumableArray2["default"])(dir.changes.unchanged));
97 });
98 return changes;
99 };
100
101 CodegenDirectory.hasChanges = function hasChanges(changes) {
102 return changes.created.length > 0 || changes.updated.length > 0 || changes.deleted.length > 0;
103 };
104
105 CodegenDirectory.printChanges = function printChanges(changes, options) {
106 require("./GraphQLCompilerProfiler").run('CodegenDirectory.printChanges', function () {
107 var output = [];
108
109 function printFiles(label, files) {
110 if (files.length > 0) {
111 output.push(label + ':');
112 files.forEach(function (file) {
113 output.push(' - ' + file);
114 });
115 }
116 }
117
118 if (options.onlyValidate) {
119 printFiles('Missing', changes.created);
120 printFiles('Out of date', changes.updated);
121 printFiles('Extra', changes.deleted);
122 } else {
123 printFiles('Created', changes.created);
124 printFiles('Updated', changes.updated);
125 printFiles('Deleted', changes.deleted);
126 output.push("Unchanged: ".concat(changes.unchanged.length, " files"));
127 } // eslint-disable-next-line no-console
128
129
130 console.log(output.join('\n'));
131 });
132 };
133
134 CodegenDirectory.getAddedRemovedFiles = function getAddedRemovedFiles(dirs) {
135 var added = [];
136 var removed = [];
137 dirs.forEach(function (dir) {
138 dir.changes.created.forEach(function (name) {
139 added.push(dir.getPath(name));
140 });
141 dir.changes.deleted.forEach(function (name) {
142 removed.push(dir.getPath(name));
143 });
144 });
145 return {
146 added: added,
147 removed: removed
148 };
149 };
150
151 CodegenDirectory.sourceControlAddRemove =
152 /*#__PURE__*/
153 function () {
154 var _sourceControlAddRemove = _asyncToGenerator(function* (sourceControl, dirs) {
155 var _CodegenDirectory$get = CodegenDirectory.getAddedRemovedFiles(dirs),
156 added = _CodegenDirectory$get.added,
157 removed = _CodegenDirectory$get.removed;
158
159 sourceControl.addRemove(added, removed);
160 });
161
162 return function sourceControlAddRemove(_x, _x2) {
163 return _sourceControlAddRemove.apply(this, arguments);
164 };
165 }();
166
167 var _proto = CodegenDirectory.prototype;
168
169 _proto.printChanges = function printChanges() {
170 CodegenDirectory.printChanges(this.changes, {
171 onlyValidate: this.onlyValidate
172 });
173 };
174
175 _proto.read = function read(filename) {
176 var filePath = require("path").join(this._dir, filename);
177
178 if (this._filesystem.existsSync(filePath)) {
179 return this._filesystem.readFileSync(filePath, 'utf8');
180 }
181
182 return null;
183 };
184
185 _proto.markUnchanged = function markUnchanged(filename) {
186 this._addGenerated(filename);
187
188 this.changes.unchanged.push(filename);
189 };
190 /**
191 * Marks a files as updated or out of date without actually writing the file.
192 * This is probably only be useful when doing validation without intention to
193 * actually write to disk.
194 */
195
196
197 _proto.markUpdated = function markUpdated(filename) {
198 this._addGenerated(filename);
199
200 this.changes.updated.push(filename);
201 };
202
203 _proto.writeFile = function writeFile(filename, content) {
204 var _this2 = this;
205
206 require("./GraphQLCompilerProfiler").run('CodegenDirectory.writeFile', function () {
207 _this2._addGenerated(filename);
208
209 var filePath = require("path").join(_this2._dir, filename);
210
211 if (_this2._filesystem.existsSync(filePath)) {
212 var existingContent = _this2._filesystem.readFileSync(filePath, 'utf8');
213
214 if (existingContent === content) {
215 _this2.changes.unchanged.push(filename);
216 } else {
217 _this2._writeFile(filePath, content);
218
219 _this2.changes.updated.push(filename);
220 }
221 } else {
222 _this2._writeFile(filePath, content);
223
224 _this2.changes.created.push(filename);
225 }
226 });
227 };
228
229 _proto._writeFile = function _writeFile(filePath, content) {
230 if (!this.onlyValidate) {
231 this._filesystem.writeFileSync(filePath, content, 'utf8');
232 }
233 };
234 /**
235 * Deletes all non-generated files, except for invisible "dot" files (ie.
236 * files with names starting with ".") and any files matching the supplied
237 * filePatternToKeep.
238 */
239
240
241 _proto.deleteExtraFiles = function deleteExtraFiles(filePatternToKeep) {
242 var _this3 = this;
243
244 require("./GraphQLCompilerProfiler").run('CodegenDirectory.deleteExtraFiles', function () {
245 _this3._filesystem.readdirSync(_this3._dir).forEach(function (actualFile) {
246 var shouldFileExist = _this3._files.has(actualFile) || /^\./.test(actualFile) || filePatternToKeep != null && filePatternToKeep.test(actualFile);
247
248 if (shouldFileExist) {
249 return;
250 }
251
252 if (!_this3.onlyValidate) {
253 try {
254 _this3._filesystem.unlinkSync(require("path").join(_this3._dir, actualFile));
255 } catch (_unused) {
256 throw new Error('CodegenDirectory: Failed to delete `' + actualFile + '` in `' + _this3._dir + '`.');
257 }
258 }
259
260 _this3.changes.deleted.push(actualFile);
261 });
262 });
263 };
264
265 _proto.getPath = function getPath(filename) {
266 return require("path").join(this._dir, filename);
267 };
268
269 _proto._addGenerated = function _addGenerated(filename) {
270 !!this._files.has(filename) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'CodegenDirectory: Tried to generate `%s` twice in `%s`.', filename, this._dir) : require("fbjs/lib/invariant")(false) : void 0;
271
272 this._files.add(filename);
273 };
274
275 return CodegenDirectory;
276}();
277
278module.exports = CodegenDirectory;
\No newline at end of file