1 | "use strict";
|
2 |
|
3 | var 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 |
|
10 | this.task = task;
|
11 |
|
12 |
|
13 | this.options = task.options(JsBeautifierTask.DEFAULT_OPTIONS);
|
14 | };
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | JsBeautifierTask.DEFAULT_OPTIONS = {
|
23 | mode: "VERIFY_AND_WRITE",
|
24 | dest: "",
|
25 | js: {},
|
26 | css: {},
|
27 | html: {}
|
28 | };
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | JsBeautifierTask.registerWithGrunt = function(grunt) {
|
36 | grunt.registerMultiTask("jsbeautifier", "jsbeautifier.org for grunt", function() {
|
37 | var task = new JsBeautifierTask(this);
|
38 | task.run();
|
39 | });
|
40 | };
|
41 |
|
42 | function 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 |
|
58 | function 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 |
|
73 | function 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 |
|
87 | if (addNewLine) {
|
88 | result += "\n";
|
89 | }
|
90 | grunt.verbose.ok();
|
91 |
|
92 | if (original != result) {
|
93 | actionHandler(file, result);
|
94 | }
|
95 | }
|
96 |
|
97 | JsBeautifierTask.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 |
|
201 | module.exports = JsBeautifierTask;
|