gulp-jsbeautifier
Version:
js-beautify for Gulp
187 lines (157 loc) • 5.16 kB
JavaScript
const beautify = require('js-beautify');
const colors = require('ansi-colors');
const cosmiconfig = require('cosmiconfig');
const log = require('fancy-log');
const mergeWith = require('lodash.mergewith');
const path = require('path');
const PluginError = require('plugin-error');
const through = require('through2');
const PLUGIN_NAME = 'gulp-jsbeautifier';
/**
* Merge options from different sources
* @param {Object} pluginOptions The gulp-jsbeautifier options
* @return {Object} The options
*/
function mergeOptions(pluginOptions) {
const defaultOptions = {
config: null,
debug: false,
css: {
file_types: ['.css', '.less', '.sass', '.scss'],
},
html: {
file_types: ['.html'],
},
js: {
file_types: ['.js', '.json'],
},
};
// Load 'file options'
const explorer = cosmiconfig('jsbeautify');
let explorerResult;
if (pluginOptions && pluginOptions.config) {
explorerResult = explorer.loadSync(path.resolve(pluginOptions.config));
} else {
explorerResult = explorer.searchSync();
}
let fileOptions;
if (explorerResult) {
fileOptions = explorerResult.config;
}
// Merge options
const finalOptions = mergeWith({}, defaultOptions, fileOptions, pluginOptions, (objValue, srcValue) => {
if (Array.isArray(objValue)) {
return objValue.concat(srcValue);
}
return undefined;
});
// Show debug messages
if (finalOptions.debug) {
if (fileOptions) {
log(`File options:\n${JSON.stringify(fileOptions, null, 2)}`);
}
log(`Final options:\n${JSON.stringify(finalOptions, null, 2)}`);
}
// Delete properties not used
delete finalOptions.config;
delete finalOptions.debug;
return finalOptions;
}
/**
* Beautify files or perform validation
* @param {Object} pluginOptions The gulp-jsbeautifier parameter options
* @param {boolean} doValidation Specifies whether perform validation only
* @return {Object} The object stream
*/
function helper(pluginOptions, doValidation) {
const options = mergeOptions(pluginOptions);
return through.obj((file, encoding, callback) => {
let oldContent;
let newContent;
let type = null;
if (file.isNull()) {
callback(null, file);
return;
}
if (file.isStream()) {
callback(new PluginError(PLUGIN_NAME, 'Streaming not supported'));
return;
}
// Check if current file should be treated as JavaScript, HTML, CSS or if it should be ignored
['js', 'css', 'html'].some((value) => {
// Check if at least one element in 'file_types' is suffix of file basename
if (options[value].file_types.some(suffix => path.basename(file.path).endsWith(suffix))) {
type = value;
return true;
}
return false;
});
// Initialize properties for reporter
file.jsbeautify = {};
file.jsbeautify.type = type;
file.jsbeautify.beautified = false;
file.jsbeautify.canBeautify = false;
if (type) {
oldContent = file.contents.toString('utf8');
newContent = beautify[type](oldContent, options);
if (oldContent.toString() !== newContent.toString()) {
if (doValidation) {
file.jsbeautify.canBeautify = true;
} else {
file.contents = Buffer.from(newContent);
file.jsbeautify.beautified = true;
}
}
}
callback(null, file);
});
}
/**
* Beautify files
* @param {Object} options The gulp-jsbeautifier parameter options
* @return {Object} The object stream with beautified files
*/
const plugin = options => helper(options, false);
/**
* Perform the validation of files without changing their content
* @param {Object} options The gulp-jsbeautifier parameter options
* @return {Object} The object stream
*/
plugin.validate = options => helper(options, true);
/**
* Show results of beautification or validation
* @param {Object} options The gulp-jsbeautifier reporter options
* @return {Object} The object stream
*/
plugin.reporter = (options) => {
let verbosity = 0;
let errorCount = 0;
if (typeof options === 'object' && Object.prototype.hasOwnProperty.call(options, 'verbosity')) {
({ verbosity } = options);
}
return through.obj((file, encoding, callback) => {
if (file.jsbeautify) {
if (verbosity >= 1 && file.jsbeautify.type === null) {
log(`Can not beautify ${colors.cyan(file.relative)}`);
} else if (verbosity >= 0 && file.jsbeautify.beautified) {
log(`Beautified ${colors.cyan(file.relative)} [${file.jsbeautify.type}]`);
} else if (verbosity >= 0 && file.jsbeautify.canBeautify) {
errorCount += 1;
log(`Can beautify ${colors.cyan(file.relative)} [${file.jsbeautify.type}]`);
} else if (verbosity >= 1) {
log(`Already beautified ${colors.cyan(file.relative)} [${file.jsbeautify.type}]`);
}
}
callback(null, file);
}, function flush(callback) {
if (errorCount > 0) {
this.emit('error', new PluginError(PLUGIN_NAME, 'Validation not passed. Please beautify.'));
}
callback();
});
};
plugin.report = {
BEAUTIFIED: 0,
ALL: 1,
};
module.exports = plugin;