1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | module.exports = function(grunt) {
|
11 |
|
12 |
|
13 | var jshint = require('jshint').JSHINT;
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | grunt.registerMultiTask('lint', 'Validate files with JSHint.', function() {
|
20 |
|
21 |
|
22 | var options, globals, tmp;
|
23 |
|
24 | tmp = grunt.config(['jshint', this.target, 'options']);
|
25 | if (typeof tmp === 'object') {
|
26 | grunt.verbose.writeln('Using "' + this.target + '" JSHint options.');
|
27 | options = tmp;
|
28 | } else {
|
29 | grunt.verbose.writeln('Using master JSHint options.');
|
30 | options = grunt.config('jshint.options');
|
31 | }
|
32 | grunt.verbose.writeflags(options, 'Options');
|
33 |
|
34 | tmp = grunt.config(['jshint', this.target, 'globals']);
|
35 | if (typeof tmp === 'object') {
|
36 | grunt.verbose.writeln('Using "' + this.target + '" JSHint globals.');
|
37 | globals = tmp;
|
38 | } else {
|
39 | grunt.verbose.writeln('Using master JSHint globals.');
|
40 | globals = grunt.config('jshint.globals');
|
41 | }
|
42 | grunt.verbose.writeflags(globals, 'Globals');
|
43 |
|
44 |
|
45 | grunt.file.expandFiles(this.file.src).forEach(function(filepath) {
|
46 | grunt.helper('lint', grunt.file.read(filepath), options, globals, filepath);
|
47 | });
|
48 |
|
49 |
|
50 | if (this.errorCount) { return false; }
|
51 |
|
52 |
|
53 | grunt.log.writeln('Lint free.');
|
54 | });
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 | function getTabStr(options) {
|
63 |
|
64 | jshint('\tx', options || {});
|
65 |
|
66 |
|
67 | var character = jshint.errors && jshint.errors[0] && jshint.errors[0].character - 1;
|
68 |
|
69 | var tabsize = isNaN(character) ? 1 : character;
|
70 |
|
71 |
|
72 | return tabsize > 1 && grunt.utils.repeat(tabsize, '\uFFFF');
|
73 | }
|
74 |
|
75 | var tabregex = /\t/g;
|
76 |
|
77 |
|
78 | grunt.registerHelper('lint', function(src, options, globals, extraMsg) {
|
79 |
|
80 | options = grunt.utils._.clone(options);
|
81 | globals = grunt.utils._.clone(globals);
|
82 |
|
83 | if (grunt.option('debug') !== undefined) {
|
84 | options.devel = options.debug = grunt.option('debug');
|
85 |
|
86 | if (grunt.option('debug')) {
|
87 | options.maxerr = Infinity;
|
88 | }
|
89 | }
|
90 | var msg = 'Linting' + (extraMsg ? ' ' + extraMsg : '') + '...';
|
91 | grunt.verbose.write(msg);
|
92 |
|
93 | var tabstr = getTabStr(options);
|
94 | var placeholderregex = new RegExp(tabstr, 'g');
|
95 |
|
96 | var result = jshint(src, options || {}, globals || {});
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | if (result) {
|
107 |
|
108 | grunt.verbose.ok();
|
109 | } else {
|
110 |
|
111 | grunt.verbose.or.write(msg);
|
112 | grunt.log.error();
|
113 |
|
114 | jshint.errors.forEach(function(e) {
|
115 |
|
116 | if (!e) { return; }
|
117 | var pos;
|
118 | var evidence = e.evidence;
|
119 | var character = e.character;
|
120 | if (evidence) {
|
121 |
|
122 | grunt.fail.errorcount++;
|
123 |
|
124 | pos = '['.red + ('L' + e.line).yellow + ':'.red + ('C' + character).yellow + ']'.red;
|
125 | grunt.log.writeln(pos + ' ' + e.reason.yellow);
|
126 |
|
127 |
|
128 | if (tabstr) {
|
129 | evidence = evidence.replace(tabregex, tabstr);
|
130 | }
|
131 | if (character > evidence.length) {
|
132 |
|
133 | evidence = evidence + ' '.inverse.red;
|
134 | } else {
|
135 |
|
136 | evidence = evidence.slice(0, character - 1) + evidence[character - 1].inverse.red +
|
137 | evidence.slice(character);
|
138 | }
|
139 |
|
140 | evidence = evidence.replace(tabstr ? placeholderregex : tabregex, ' ');
|
141 | grunt.log.writeln(evidence);
|
142 | } else {
|
143 |
|
144 | grunt.log.error(e.reason);
|
145 | }
|
146 | });
|
147 | grunt.log.writeln();
|
148 | }
|
149 | });
|
150 |
|
151 | };
|