285 lines
8.7 KiB
JavaScript
285 lines
8.7 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* strict-local
|
|
* @format
|
|
*/
|
|
'use strict';
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
|
|
var _asyncToGenerator = require("@babel/runtime/helpers/asyncToGenerator");
|
|
|
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
|
|
var Profiler = require("./GraphQLCompilerProfiler");
|
|
|
|
var invariant = require("fbjs/lib/invariant");
|
|
|
|
var path = require("path");
|
|
|
|
/**
|
|
* CodegenDirectory is a helper class for scripts that generate code into one
|
|
* output directory. The purpose is to make it easy to only write files that
|
|
* have changed and delete files that are no longer generated.
|
|
* It gives statistics about added/removed/updated/unchanged in the end.
|
|
* The class also has an option to "validate" which means that no file
|
|
* operations are performed and only the statistics are created for what would
|
|
* have happened. If there's anything but "unchanged", someone probably forgot
|
|
* to run the codegen script.
|
|
*
|
|
* Example:
|
|
*
|
|
* const dir = new CodegenDirectory('/some/path/generated', {filesystem: require('fs')});
|
|
* // write files in case content changed (less watchman/mtime changes)
|
|
* dir.writeFile('OneFile.js', contents);
|
|
* dir.writeFile('OtherFile.js', contents);
|
|
*
|
|
* // delete files that are not generated
|
|
* dir.deleteExtraFiles();
|
|
*
|
|
* // arrays of file names to print or whatever
|
|
* dir.changes.created
|
|
* dir.changes.updated
|
|
* dir.changes.deleted
|
|
* dir.changes.unchanged
|
|
*/
|
|
var CodegenDirectory =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function CodegenDirectory(dir, _ref) {
|
|
var _this = this;
|
|
|
|
var filesystem = _ref.filesystem,
|
|
onlyValidate = _ref.onlyValidate;
|
|
this._filesystem = filesystem || require("fs");
|
|
this.onlyValidate = onlyValidate;
|
|
|
|
if (this._filesystem.existsSync(dir)) {
|
|
!this._filesystem.statSync(dir).isDirectory() ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected `%s` to be a directory.', dir) : invariant(false) : void 0;
|
|
} else if (!this.onlyValidate) {
|
|
var dirs = [dir];
|
|
var parent = path.dirname(dir);
|
|
|
|
while (!this._filesystem.existsSync(parent)) {
|
|
dirs.unshift(parent);
|
|
parent = path.dirname(parent);
|
|
}
|
|
|
|
dirs.forEach(function (d) {
|
|
return _this._filesystem.mkdirSync(d);
|
|
});
|
|
}
|
|
|
|
this._files = new Set();
|
|
this.changes = {
|
|
deleted: [],
|
|
updated: [],
|
|
created: [],
|
|
unchanged: []
|
|
};
|
|
this._dir = dir;
|
|
}
|
|
|
|
CodegenDirectory.combineChanges = function combineChanges(dirs) {
|
|
var changes = {
|
|
deleted: [],
|
|
updated: [],
|
|
created: [],
|
|
unchanged: []
|
|
};
|
|
dirs.forEach(function (dir) {
|
|
var _changes$deleted, _changes$updated, _changes$created, _changes$unchanged;
|
|
|
|
(_changes$deleted = changes.deleted).push.apply(_changes$deleted, (0, _toConsumableArray2["default"])(dir.changes.deleted));
|
|
|
|
(_changes$updated = changes.updated).push.apply(_changes$updated, (0, _toConsumableArray2["default"])(dir.changes.updated));
|
|
|
|
(_changes$created = changes.created).push.apply(_changes$created, (0, _toConsumableArray2["default"])(dir.changes.created));
|
|
|
|
(_changes$unchanged = changes.unchanged).push.apply(_changes$unchanged, (0, _toConsumableArray2["default"])(dir.changes.unchanged));
|
|
});
|
|
return changes;
|
|
};
|
|
|
|
CodegenDirectory.hasChanges = function hasChanges(changes) {
|
|
return changes.created.length > 0 || changes.updated.length > 0 || changes.deleted.length > 0;
|
|
};
|
|
|
|
CodegenDirectory.printChanges = function printChanges(changes, options) {
|
|
Profiler.run('CodegenDirectory.printChanges', function () {
|
|
var output = [];
|
|
|
|
function printFiles(label, files) {
|
|
if (files.length > 0) {
|
|
output.push(label + ':');
|
|
files.forEach(function (file) {
|
|
output.push(' - ' + file);
|
|
});
|
|
}
|
|
}
|
|
|
|
if (options.onlyValidate) {
|
|
printFiles('Missing', changes.created);
|
|
printFiles('Out of date', changes.updated);
|
|
printFiles('Extra', changes.deleted);
|
|
} else {
|
|
printFiles('Created', changes.created);
|
|
printFiles('Updated', changes.updated);
|
|
printFiles('Deleted', changes.deleted);
|
|
output.push("Unchanged: ".concat(changes.unchanged.length, " files"));
|
|
} // eslint-disable-next-line no-console
|
|
|
|
|
|
console.log(output.join('\n'));
|
|
});
|
|
};
|
|
|
|
CodegenDirectory.getAddedRemovedFiles = function getAddedRemovedFiles(dirs) {
|
|
var added = [];
|
|
var removed = [];
|
|
dirs.forEach(function (dir) {
|
|
dir.changes.created.forEach(function (name) {
|
|
added.push(dir.getPath(name));
|
|
});
|
|
dir.changes.deleted.forEach(function (name) {
|
|
removed.push(dir.getPath(name));
|
|
});
|
|
});
|
|
return {
|
|
added: added,
|
|
removed: removed
|
|
};
|
|
};
|
|
|
|
CodegenDirectory.sourceControlAddRemove =
|
|
/*#__PURE__*/
|
|
function () {
|
|
var _sourceControlAddRemove = _asyncToGenerator(function* (sourceControl, dirs) {
|
|
var _CodegenDirectory$get = CodegenDirectory.getAddedRemovedFiles(dirs),
|
|
added = _CodegenDirectory$get.added,
|
|
removed = _CodegenDirectory$get.removed;
|
|
|
|
sourceControl.addRemove(added, removed);
|
|
});
|
|
|
|
return function sourceControlAddRemove(_x, _x2) {
|
|
return _sourceControlAddRemove.apply(this, arguments);
|
|
};
|
|
}();
|
|
|
|
var _proto = CodegenDirectory.prototype;
|
|
|
|
_proto.printChanges = function printChanges() {
|
|
CodegenDirectory.printChanges(this.changes, {
|
|
onlyValidate: this.onlyValidate
|
|
});
|
|
};
|
|
|
|
_proto.read = function read(filename) {
|
|
var filePath = path.join(this._dir, filename);
|
|
|
|
if (this._filesystem.existsSync(filePath)) {
|
|
return this._filesystem.readFileSync(filePath, 'utf8');
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
_proto.markUnchanged = function markUnchanged(filename) {
|
|
this._addGenerated(filename);
|
|
|
|
this.changes.unchanged.push(filename);
|
|
};
|
|
/**
|
|
* Marks a files as updated or out of date without actually writing the file.
|
|
* This is probably only be useful when doing validation without intention to
|
|
* actually write to disk.
|
|
*/
|
|
|
|
|
|
_proto.markUpdated = function markUpdated(filename) {
|
|
this._addGenerated(filename);
|
|
|
|
this.changes.updated.push(filename);
|
|
};
|
|
|
|
_proto.writeFile = function writeFile(filename, content) {
|
|
var _this2 = this;
|
|
|
|
Profiler.run('CodegenDirectory.writeFile', function () {
|
|
_this2._addGenerated(filename);
|
|
|
|
var filePath = path.join(_this2._dir, filename);
|
|
|
|
if (_this2._filesystem.existsSync(filePath)) {
|
|
var existingContent = _this2._filesystem.readFileSync(filePath, 'utf8');
|
|
|
|
if (existingContent === content) {
|
|
_this2.changes.unchanged.push(filename);
|
|
} else {
|
|
_this2._writeFile(filePath, content);
|
|
|
|
_this2.changes.updated.push(filename);
|
|
}
|
|
} else {
|
|
_this2._writeFile(filePath, content);
|
|
|
|
_this2.changes.created.push(filename);
|
|
}
|
|
});
|
|
};
|
|
|
|
_proto._writeFile = function _writeFile(filePath, content) {
|
|
if (!this.onlyValidate) {
|
|
this._filesystem.writeFileSync(filePath, content, 'utf8');
|
|
}
|
|
};
|
|
/**
|
|
* Deletes all non-generated files, except for invisible "dot" files (ie.
|
|
* files with names starting with ".") and any files matching the supplied
|
|
* filePatternToKeep.
|
|
*/
|
|
|
|
|
|
_proto.deleteExtraFiles = function deleteExtraFiles(filePatternToKeep) {
|
|
var _this3 = this;
|
|
|
|
Profiler.run('CodegenDirectory.deleteExtraFiles', function () {
|
|
_this3._filesystem.readdirSync(_this3._dir).forEach(function (actualFile) {
|
|
var shouldFileExist = _this3._files.has(actualFile) || /^\./.test(actualFile) || filePatternToKeep != null && filePatternToKeep.test(actualFile);
|
|
|
|
if (shouldFileExist) {
|
|
return;
|
|
}
|
|
|
|
if (!_this3.onlyValidate) {
|
|
try {
|
|
_this3._filesystem.unlinkSync(path.join(_this3._dir, actualFile));
|
|
} catch (_unused) {
|
|
throw new Error('CodegenDirectory: Failed to delete `' + actualFile + '` in `' + _this3._dir + '`.');
|
|
}
|
|
}
|
|
|
|
_this3.changes.deleted.push(actualFile);
|
|
});
|
|
});
|
|
};
|
|
|
|
_proto.getPath = function getPath(filename) {
|
|
return path.join(this._dir, filename);
|
|
};
|
|
|
|
_proto._addGenerated = function _addGenerated(filename) {
|
|
!!this._files.has(filename) ? process.env.NODE_ENV !== "production" ? invariant(false, 'CodegenDirectory: Tried to generate `%s` twice in `%s`.', filename, this._dir) : invariant(false) : void 0;
|
|
|
|
this._files.add(filename);
|
|
};
|
|
|
|
return CodegenDirectory;
|
|
}();
|
|
|
|
module.exports = CodegenDirectory; |