File Coverage

blib/lib/JavaScript/JSLint.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             # @(#) $Id$
2              
3             package JavaScript::JSLint;
4              
5 1     1   39607 use strict;
  1         3  
  1         47  
6 1     1   6 use warnings;
  1         1  
  1         38  
7              
8 1     1   5 use Carp;
  1         6  
  1         70  
9 1     1   441 use JavaScript;
  0            
  0            
10             use JSON qw(encode_json);
11              
12             use base qw( Exporter );
13              
14             our @EXPORT = qw( jslint );
15             our @EXPORT_OK = qw( jslint jslint_options );
16              
17             our $VERSION = '0.07';
18              
19              
20             my %JSLINT_OPTIONS = (
21             adsafe => {type => 'bool', desc => 'ADsafe rules should be enforced'},
22             bitwise => {type => 'bool', desc => 'bitwise operators should be allowed'},
23             browser => {type => 'bool', desc => 'the standard browser globals should be predefined'},
24             confusion => {type => 'bool', desc => 'types can be used inconsistently'},
25             'continue' => {type => 'bool', desc => 'the continuation statement should be tolerated'},
26             debug => {type => 'bool', desc => 'debugger statements should be allowed'},
27             devel => {type => 'bool', desc => 'logging should be allowed (console, alert, etc.)'},
28             eqeq => {type => 'bool', desc => '== should be allowed'},
29             es5 => {type => 'bool', desc => 'ES5 syntax should be allowed'},
30             evil => {type => 'bool', desc => 'eval should be allowed'},
31             forin => {type => 'bool', desc => 'for in statements need not filter'},
32             fragment => {type => 'bool', desc => 'HTML fragments should be allowed'},
33             indent => {type => 'int', desc => 'the indentation factor'},
34             maxerr => {type => 'int', desc => 'the maximum number of errors to allow'},
35             maxlen => {type => 'int', desc => 'the maximum length of a source line'},
36             newcap => {type => 'bool', desc => 'constructor names capitalization is ignored'},
37             node => {type => 'bool', desc => 'Node.js globals should be predefined'},
38             nomen => {type => 'bool', desc => 'names may have dangling _'},
39             on => {type => 'bool', desc => 'HTML event handlers should be allowed'},
40             passfail => {type => 'bool', desc => 'the scan should stop on first error'},
41             plusplus => {type => 'bool', desc => 'increment/decrement should be allowed'},
42             properties => {type => 'bool', desc => 'all property names must be declared with /*properties*/'},
43             predef => {type => 'hash', desc => 'predefine global variables'},
44             regexp => {type => 'bool', desc => 'the . should be allowed in regexp literals'},
45             rhino => {type => 'bool', desc => 'the Rhino environment globals should be predefined'},
46             'undef' => {type => 'bool', desc => 'variables can be declared out of order'},
47             unparam => {type => 'bool', desc => 'unused parameters should be tolerated'},
48             safe => {type => 'bool', desc => 'use of some browser features should be restricted'},
49             sloppy => {type => 'bool', desc => 'the \'use strict\'; pragma is optional'},
50             'sub' => {type => 'bool', desc => 'all forms of subscript notation are tolerated'},
51             vars => {type => 'bool', desc => 'multiple var statements per function should be allowed'},
52             white => {type => 'bool', desc => 'sloppy whitespace is tolerated'},
53             widget => {type => 'bool', desc => 'the Yahoo Widgets globals should be predefined'},
54             windows => {type => 'bool', desc => 'MS Windows-specific globals should be predefined'},
55             );
56              
57              
58              
59             {
60             my $ctx;
61             my $jslint_source = do { local $/; };
62              
63             sub _get_context {
64             unless ( $ctx ) {
65             $ctx = JavaScript::Runtime->new()->create_context();
66             $ctx->eval( $jslint_source, "fulljslint.js" );
67             }
68             return $ctx;
69             }
70             }
71              
72             sub _make_fatal_error {
73             my ( $err ) = @_;
74             my %newerr = %$err;
75             $newerr{ id } = '(fatal)';
76             $newerr{ reason } = 'Cannot proceed.';
77             return \%newerr;
78             }
79              
80             sub jslint {
81             my ( $js_source, %opt ) = @_;
82             croak "usage: jslint(js_source)"
83             unless defined $js_source;
84             my $ctx = _get_context();
85              
86             my $js_source_str = encode_json(
87             [ split(/\n/, $js_source) ]
88             );
89              
90             my $predef = $opt{predef} || {};
91             if ( $predef && ref $predef eq 'HASH' ) {
92             %{$predef} = map {
93             $_ => ( $predef->{$_} ? JSON::true : JSON::false )
94             } keys %{$predef};
95             }
96             $opt{predef} = $predef;
97              
98             my $opt_str = encode_json( {
99             map {
100             $_ => (
101             ($JSLINT_OPTIONS{$_} && $JSLINT_OPTIONS{$_}->{type} eq 'bool')
102             ? ( $opt{$_} ? JSON::true : JSON::false )
103             : $opt{$_}
104             );
105             } keys %opt
106             } );
107              
108             my $ok = $ctx->eval(qq/
109             JSLINT($js_source_str,$opt_str);
110             /);
111            
112             die "$@" if $@;
113             if ( $ok ) {
114             return;
115             }
116             else {
117             my @errors = @{ $ctx->eval( "JSLINT.errors" ) };
118             # Remove the trailing undefined value, which JSLint returns if it's
119             # unable to proceed.
120             pop @errors if !defined $errors[-1];
121             return @errors;
122             # I don't think this is necessary any longer
123             #return map { _fix_line_and_char_numbers( $_ ) } @errors;
124             }
125             }
126              
127             # TODO: generate this list by parsing the source below.
128             sub jslint_options {
129             my $want_full_options = shift;
130             return map {
131             $_ => $want_full_options ? $JSLINT_OPTIONS{$_} : $JSLINT_OPTIONS{$_}->{desc}
132             } keys %JSLINT_OPTIONS;
133             }
134              
135              
136             1;
137              
138             =head1 NAME
139              
140             JavaScript::JSLint - Check JavaScript code for problems
141              
142             =head1 SYNOPSIS
143              
144             use JavaScript::JSLint;
145            
146             my @errors = jslint( $javascript, white => 1 );
147             foreach my $err (@errors) {
148             print "$err->{reason} at line $err->{line}\n";
149             }
150              
151             =head1 DESCRIPTION
152              
153             JavaScript::JSLint is a tool for checking for common problems in
154             JavaScript code. It's based on Douglas Crockford's jslint. Full
155             documentation on the conditions that it detects is at
156             L.
157              
158             You may be more interested in the command line interface, L.
159              
160             =head2 EXPORT
161              
162             =over 4
163              
164             =item jslint()
165              
166             This takes one mandatory parameter: a string containing JavaScript code.
167             It returns a list of errors. If there are no problems, an empty list will
168             be returned. Each error is a hash reference containing these keys:
169              
170             =over 4
171              
172             =item I
173              
174             The category of error.
175              
176             =item I
177              
178             The line number of the error.
179              
180             =item I
181              
182             The character on the line where the error occurs.
183              
184             =item I
185              
186             Descriptive text of the error.
187              
188             =item I
189              
190             A copy of the line of code that produced the error.
191              
192             =back
193              
194             In addition to pure JavaScript, you can also pass in a piece of HTML
195             code. This will be parsed and any JavaScript found within will be
196             checked in the usual manner. The HTML code must be a full web page,
197             i.e. start with C<< >>.
198              
199             You can optionally pass in a second parameter to influence how JSLint works.
200             The following keys are used. Most take a boolean value, which is false by
201             default.
202              
203             =over 4
204              
205             =item I
206              
207             true, if ADsafe rules should be enforced
208              
209             =item I
210              
211             true, if bitwise operators should be allowed
212              
213             =item I
214              
215             true, if the standard browser globals should be predefined
216              
217             =item I
218              
219             true, if types can be used inconsistently
220              
221             =item I
222              
223             true, if the continuation statement should be tolerated
224              
225             =item I
226              
227             true, if debugger statements should be allowed
228              
229             =item I
230              
231             true, if logging should be allowed (console, alert, etc.)
232              
233             =item I
234              
235             true, if C<==> should be allowed
236              
237             =item I
238              
239             true, if ES5 syntax should be allowed
240              
241             =item I
242              
243             true, if eval should be allowed
244              
245             =item I
246              
247             true, if C statements need not filter
248              
249             =item I
250              
251             true, if HTML fragments should be allowed
252              
253             =item I
254              
255             the indentation factor
256              
257             =item I
258              
259             the maximum number of errors to allow
260              
261             =item I
262              
263             the maximum length of a source line
264              
265             =item I
266              
267             true, if constructor names capitalization is ignored
268              
269             =item I
270              
271             true, if Node.js globals should be predefined
272              
273             =item I
274              
275             true, if names may have dangling C<_>
276              
277             =item I
278              
279             true, if HTML event handlers should be allowed
280              
281             =item I
282              
283             true, if the scan should stop on first error
284              
285             =item I
286              
287             true, if increment/decrement should be allowed
288              
289             =item I
290              
291             true, if all property names must be declared with C
292              
293             =item I
294              
295             predefine variables as globals. A reference to either an array or a hash. If an
296             arrayref, the elements of the array should be the names of the variables to be
297             predefined. If a hashref, the keys are the variable names to be defined and the
298             values indicate whether a variable is assignable (C<1>) or not (C<0>).
299              
300             =item I
301              
302             true, if C<.> and C<[^...]> should be allowed in regexp literals
303              
304             =item I
305              
306             true, if the Rhino environment globals should be predefined
307              
308             =item I
309              
310             true, if variables can be declared out of order
311              
312             =item I
313              
314             true, if unused parameters should be tolerated
315              
316             =item I
317              
318             true, if use of some browser features should be restricted
319              
320             =item I
321              
322             true, if the \'use strict\'; pragma is optional
323              
324             =item I
325              
326             true, if all forms of subscript notation are tolerated
327              
328             =item I
329              
330             true, if multiple C statements per function should be allowed
331              
332             =item I
333              
334             true, if sloppy whitespace is tolerated
335              
336             =item I
337              
338             true, if the Yahoo Widgets globals should be predefined
339              
340             =item I
341              
342             true, if MS Windows-specific globals should be predefined
343              
344             =back
345              
346             =item jslint_options ( )
347              
348             Returns a hash of options and their descriptions. Each key is a valid option
349             to pass in to jslint().
350              
351             =back
352              
353             =head1 SEE ALSO
354              
355             L for the original version that this is based upon.
356              
357             L for more details on the Perl / JavaScript bridge.
358              
359             L for the command line interface.
360              
361             L is an alternative implementation of a
362             JavaScript lint tool.
363              
364             =head1 AUTHOR
365              
366             Dominic Mitchell, Ecpan (at) happygiraffe.netE
367              
368             Steve Webster, Ecpan (at) statichtml.comE
369              
370             =head1 COPYRIGHT AND LICENSE
371              
372             Copyright (C) 2006 by Dominic Mitchell
373              
374             Portions copyright (C) 2011 by Steve Webster
375              
376             Redistribution and use in source and binary forms, with or without
377             modification, are permitted provided that the following conditions
378             are met:
379              
380             =over 4
381              
382             =item 1.
383              
384             Redistributions of source code must retain the above copyright notice,
385             this list of conditions and the following disclaimer.
386              
387             =item 2.
388              
389             Redistributions in binary form must reproduce the above copyright
390             notice, this list of conditions and the following disclaimer in the
391             documentation and/or other materials provided with the distribution.
392              
393             =back
394              
395             THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
396             ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
397             IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
398             ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
399             FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
400             DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
401             OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
402             HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
403             LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
404             OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
405             SUCH DAMAGE.
406              
407             JSLint is originally Copyright (C) 2002 Douglas Crockford.
408              
409             =cut
410              
411             # http://www.jslint.com/fulljslint.js
412             __DATA__