123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- var fs = require('fs');
- var path = require('path');
- var crypto = require('crypto');
- /**
- * Configuration Options:
- * - write file location
- * - read file location
- */
- function checkProperty(obj, prop) {
- return Object.prototype.hasOwnProperty.call(obj, prop);
- }
- /**
- * Generates a 'random' hex value.
- * More 'random' than Math.random without depending on a GUID module.
- */
- function generateRandomIdentifier() {
- return crypto.randomBytes(4).toString('hex');
- }
- /**
- * Escapes illegal characters from filename
- * Ref: https://github.com/aws/aws-sdk-js/issues/3691
- */
- function sanitizeFileName(filename) {
- return filename.replace(/[^a-zA-Z0-9\\.]/g, '-');
- }
- var CHANGES_DIR = path.join(process.cwd(), '.changes');
- /**
- * A map of valid change types.
- * Can be referenced outside of this module.
- */
- var VALID_TYPES = Object.create(null);
- VALID_TYPES['bugfix'] = true;
- VALID_TYPES['feature'] = true;
- /**
- * Handles creating a change log entry JSON file.
- */
- function ChangeCreator(config) {
- this._config = config || {};
- this._type = '';
- this._category = '';
- this._description = '';
- }
- ChangeCreator.prototype = {
- getChangeType: function getChangeType() {
- return this._type;
- },
- setChangeType: function setChangeType(type) {
- this._type = type;
- },
- getChangeCategory: function getChangeCategory() {
- return this._category;
- },
- setChangeCategory: function setChangeCategory(category) {
- this._category = category;
- },
- getChangeDescription: function getChangeDescription() {
- return this._description;
- },
- setChangeDescription: function setChangeDescription(description) {
- this._description = description;
- },
- /**
- * Validates the entire change entry.
- */
- validateChange: function validateChange() {
- var type = this.getChangeType();
- var category = this.getChangeCategory();
- var description = this.getChangeDescription();
- var missingFields = [];
- this.validateChangeType(type);
- this.validateChangeCategory(category);
- this.validateChangeDescription(description);
- return this;
- },
- /**
- * Validates a change entry type.
- */
- validateChangeType: function validateChangeType(type) {
- var type = type || this._type;
- if (!type) {
- throw new Error('ValidationError: Missing `type` field.');
- }
- if (VALID_TYPES[type]) {
- return this;
- }
- var validTypes = Object.keys(VALID_TYPES).join(',');
- throw new Error('ValidationError: `type` set as "' + type + '" but must be one of [' + validTypes + '].');
- },
- /**
- * Validates a change entry category.
- */
- validateChangeCategory: function validateChangeCategory(category) {
- var category = category || this._category;
- if (!category) {
- throw new Error('ValidationError: Missing `category` field.');
- }
- return this;
- },
- /**
- * Validates a change entry description.
- */
- validateChangeDescription: function validateChangeDescription(description) {
- var description = description || this._description;
- if (!description) {
- throw new Error('ValidationError: Missing `description` field.');
- }
- return this;
- },
- /**
- * Creates the output directory if it doesn't exist.
- */
- createOutputDirectory: function createOutputDirectory(outPath) {
- var pathObj = path.parse(outPath);
- var sep = path.sep;
- var directoryStructure = pathObj.dir.split(sep) || [];
- for (var i = 0; i < directoryStructure.length; i++) {
- var pathToCheck = directoryStructure.slice(0, i + 1).join(sep);
- if (!pathToCheck) {
- continue;
- }
- try {
- var stats = fs.statSync(pathToCheck);
- } catch (err) {
- if (err.code === 'ENOENT') {
- // Directory doesn't exist, so create it
- fs.mkdirSync(pathToCheck);
- } else {
- throw err;
- }
- }
- }
- return this;
- },
- /**
- * Returns a path to the future change entry file.
- */
- determineWriteLocation: function determineWriteLocation() {
- /* Order for determining write location:
- 1) Check configuration for `outFile` location.
- 2) Check configuration for `inFile` location.
- 3) Create a new file using default location.
- */
- var config = this._config || {};
- if (checkProperty(config, 'outFile') && config['outFile']) {
- return config['outFile'];
- }
- if (checkProperty(config, 'inFile') && config['inFile']) {
- return config['inFile'];
- }
- // Determine default location
- var newFileName = sanitizeFileName(this._type) + '-' + sanitizeFileName(this._category)
- + '-' + generateRandomIdentifier() + '.json';
- return path.join(process.cwd(), '.changes', 'next-release', newFileName);
- },
- /**
- * Writes a change entry as a JSON file.
- */
- writeChanges: function writeChanges(callback) {
- var hasCallback = typeof callback === 'function';
- var fileLocation = this.determineWriteLocation();
- try {
- // Will throw an error if the change is not valid
- this.validateChange().createOutputDirectory(fileLocation);
- var change = {
- type: this.getChangeType(),
- category: this.getChangeCategory(),
- description: this.getChangeDescription()
- }
- fs.writeFileSync(fileLocation, JSON.stringify(change, null, 2));
- var data = {
- file: fileLocation
- };
- if (hasCallback) {
- return callback(null, data);
- } else {
- return data;
- }
- } catch (err) {
- if (hasCallback) {
- return callback(err, null);
- } else {
- throw err;
- }
- }
- }
- }
- module.exports = {
- ChangeCreator: ChangeCreator,
- VALID_TYPES: VALID_TYPES
- };
|