UNPKG

6.34 kBJavaScriptView Raw
1"use strict";
2
3var path = require("path"),
4 grunt = require('grunt'),
5 jsBeautify = require("js-beautify"),
6 _ = require("lodash"),
7 stringUtils = require("underscore.string"),
8 JsBeautifierTask = function(task) {
9 // Store reference to original task
10 this.task = task;
11
12 // Merge task options with defaults
13 this.options = task.options(JsBeautifierTask.DEFAULT_OPTIONS);
14 };
15
16/**
17 * Default options that will be merged with options specified in
18 * the original task.
19 *
20 * @type {*}
21 */
22JsBeautifierTask.DEFAULT_OPTIONS = {
23 mode: "VERIFY_AND_WRITE",
24 dest: "",
25 js: {},
26 css: {},
27 html: {}
28};
29
30/**
31 * Static method for registering an instance of the task with Grunt.
32 *
33 * @param {*} grunt
34 */
35JsBeautifierTask.registerWithGrunt = function(grunt) {
36 grunt.registerMultiTask("jsbeautifier", "jsbeautifier.org for grunt", function() {
37 var task = new JsBeautifierTask(this);
38 task.run();
39 });
40};
41
42function getFileType(file, config) {
43 var fileType = null,
44 fileMapping = {
45 "js": config.js.fileTypes,
46 "css": config.css.fileTypes,
47 "html": config.html.fileTypes
48 };
49 _.forEach(fileMapping, function(extensions, type) {
50 fileType = type;
51 return -1 === _.findIndex(extensions, function(ext) {
52 return stringUtils.endsWith(file, ext);
53 });
54 });
55 return fileType;
56}
57
58function getBeautifierSetup(file, config) {
59 var fileType = getFileType(file, config);
60 switch (fileType) {
61 case "js":
62 return [jsBeautify.js, config.js, true];
63 case "css":
64 return [jsBeautify.css, config.css];
65 case "html":
66 return [jsBeautify.html, config.html];
67 default:
68 grunt.fail.warn("Cannot beautify " + file.cyan + " (only js, css and html files can be beautified)");
69 return null;
70 }
71}
72
73function beautify(file, config, actionHandler) {
74 var setup = getBeautifierSetup(file, config);
75 if (!setup) {
76 return;
77 }
78
79 var beautifier = setup[0],
80 beautifyConfig = setup[1],
81 addNewLine = setup[2];
82
83 var original = grunt.file.read(file);
84 grunt.verbose.write("Beautifying " + file.cyan + "...");
85 var result = beautifier(original, beautifyConfig);
86 // jsbeautifier would skip the line terminator for js files
87 if (addNewLine) {
88 result += "\n";
89 }
90 grunt.verbose.ok();
91 /*jshint eqeqeq: false */
92 if (original != result) {
93 actionHandler(file, result);
94 }
95}
96
97JsBeautifierTask.prototype.run = function() {
98 var options = this.options;
99
100 var fileCount = 0,
101 changedFileCount = 0,
102 unVerifiedFiles = [];
103
104 function verifyActionHandler(src) {
105 unVerifiedFiles.push(src);
106 }
107
108 function verifyAndWriteActionHandler(src, result) {
109 grunt.verbose.writeln(options.dest + src);
110 grunt.file.write(options.dest + src, result);
111 changedFileCount++;
112 }
113
114 function convertCamelCaseToUnderScore(config) {
115 var underscoreKey;
116 _.forEach([config.js, config.css, config.html], function(conf) {
117 _.forEach(conf, function(value, key) {
118 underscoreKey = stringUtils.underscored(key);
119 if ("fileTypes" !== key && key !== underscoreKey) {
120 conf[underscoreKey] = value;
121 delete conf[key];
122 }
123 });
124 });
125 }
126
127 function getConfig() {
128 var config,
129 rcFile = require("rc")("jsbeautifier", {});
130
131 if (options.config || !_.isEqual(rcFile, {})) {
132 var baseConfig = options.config ? grunt.file.readJSON(path.resolve(options.config)) : rcFile;
133 config = {
134 js: {},
135 css: {},
136 html: {}
137 };
138 _.extend(config.js, baseConfig);
139 _.extend(config.css, baseConfig);
140 _.extend(config.html, baseConfig);
141 _.extend(config.js, baseConfig.js);
142 _.extend(config.css, baseConfig.css);
143 _.extend(config.html, baseConfig.html);
144 _.extend(config.js, options.js);
145 _.extend(config.css, options.css);
146 _.extend(config.html, options.html);
147 } else {
148 config = options;
149 }
150 config.js.fileTypes = _.union(config.js.fileTypes, [".js", ".json"]);
151 config.css.fileTypes = _.union(config.css.fileTypes, [".css"]);
152 config.html.fileTypes = _.union(config.html.fileTypes, [".html"]);
153
154 grunt.verbose.writeln("Beautify config before converting camelcase to underscore: " + JSON.stringify(config));
155
156 convertCamelCaseToUnderScore(config);
157
158 grunt.verbose.writeln("Using beautify config: " + JSON.stringify(config));
159 return config;
160 }
161
162 var sourceFiles = this.task.files;
163 if (sourceFiles && sourceFiles.length > 0) {
164 if (!_.isEmpty(options.dest)) {
165 grunt.verbose.writeln("All beautified files will be stored under \"" + options.dest + "\" folder");
166 if (!stringUtils.endsWith(options.dest, "/")) {
167 options.dest += "/";
168 }
169 }
170
171 grunt.verbose.writeln("Using mode=\"" + options.mode + "\"...");
172 var actionHandler = "VERIFY_ONLY" === options.mode ? verifyActionHandler : verifyAndWriteActionHandler,
173 config = getConfig(),
174 done = this.task.async(),
175 q = grunt.util.async.queue(function(src, callback) {
176 if (grunt.file.isDir(src)) {
177 callback();
178 return;
179 }
180
181 beautify(src, config, actionHandler);
182 fileCount++;
183 callback();
184 }, 10);
185
186 q.drain = function() {
187 if (unVerifiedFiles.length) {
188 grunt.fail.warn("The following files are not beautified:\n" + unVerifiedFiles.join("\n").cyan + "\n");
189 }
190 grunt.log.write("Beautified " + fileCount.toString().cyan + " files, changed " + changedFileCount.toString().cyan + " files...");
191 grunt.log.ok();
192 done();
193 };
194
195 sourceFiles.forEach(function(fileset) {
196 q.push(fileset.src);
197 });
198 }
199};
200
201module.exports = JsBeautifierTask;