jslint_on_rails 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jakub Suder
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,167 @@
1
+ # JSLint on Rails
2
+
3
+ **JSLint on Rails** is a Ruby gem and Rails plugin which lets you run
4
+ the [JSLint JavaScript code checker](http://jslint.com) on your Javascript code easily.
5
+
6
+ It can be installed either as a Rails plugin (the recommended method for Rails), or as a gem (for other frameworks).
7
+
8
+ Note: to run JSLint on Rails, you need to have **Java** available on your machine - it's required because JSLint is
9
+ itself written in JavaScript, and is run using the [Rhino](http://www.mozilla.org/rhino) JavaScript engine (written in
10
+ Java). Any decent version of Java will do (and by decent I mean 5.0 or later).
11
+
12
+
13
+ ## Installation (Rails)
14
+
15
+ If you use Rails, you can install the library as a plugin - it's less work to set it up this way.
16
+ To install the plugin, use this command:
17
+
18
+ ./script/plugin install git://github.com/psionides/jslint_on_rails.git
19
+
20
+ This will create for you a sample `jslint.yml` config file in your config directory.
21
+
22
+
23
+ ## Installation (other frameworks)
24
+
25
+ If you use Merb or some other framework, you need to install JSLint as a Ruby gem (you can do that in Rails too - the
26
+ advantage of this method is that it may be easier to update to newer versions later).
27
+
28
+ To use JSLint as a gem, follow these steps:
29
+
30
+ * install the gem in your application using whatever technique is recommended for your framework (e.g. using gem
31
+ bundler, or just plain old `gem install jslint_on_rails`)
32
+ * in your Rakefile, add a line to load the JSLint tasks:
33
+
34
+ require 'jslint/tasks'
35
+
36
+ * below that line, set JSLint's config_path variable to point it to a place where you want your JSLint configuration
37
+ file to be kept - for example:
38
+
39
+ JSLint.config_path = "config/jslint.yml"
40
+
41
+ * run a rake task which will generate a sample config file for you:
42
+
43
+ rake jslint:copy_config
44
+
45
+
46
+ ## Installation (custom)
47
+
48
+ If you wish to write your own rake task to run JSLint, you can create and execute the JSLint object manually:
49
+
50
+ require 'jslint'
51
+ lint = JSLint::Lint.new(
52
+ :paths => ['public/javascripts/**/*.js'],
53
+ :exclude_paths => ['public/javascripts/vendor/**/*.js'],
54
+ :config_path => 'config/jslint.yml'
55
+ )
56
+ lint.run
57
+
58
+
59
+ ## Configuration
60
+
61
+ Whatever method you use for installation, a YAML config file should be created for you. In this file, you can:
62
+
63
+ * define which Javascript files are checked by default; you'll almost certainly want to change that, because the default
64
+ is `public/javascripts/**/*.js` which means all Javascript files, and you probably don't want JSLint to check entire
65
+ jQuery, Prototype or whatever other libraries you use - so change this so that only your scripts are checked (you can
66
+ put multiple entries under "paths:" and "exclude_paths:")
67
+ * tweak JSLint options to enable or disable specific checks - I've set the defaults to what I believe is reasonable,
68
+ but what's reasonable for me may not be reasonable for you
69
+
70
+
71
+ ## Running
72
+
73
+ To start the check, run the rake task:
74
+
75
+ rake jslint
76
+
77
+ You will get a result like this (if everything goes well):
78
+
79
+ Running JSLint:
80
+
81
+ checking public/javascripts/Event.js... OK
82
+ checking public/javascripts/Map.js... OK
83
+ checking public/javascripts/Marker.js... OK
84
+ checking public/javascripts/Reports.js... OK
85
+
86
+ No JS errors found.
87
+
88
+ If anything is wrong, you will get something like this instead:
89
+
90
+ Running JSLint:
91
+
92
+ checking public/javascripts/Event.js... 2 errors:
93
+
94
+ Lint at line 24 character 15: Use '===' to compare with 'null'.
95
+ if (a == null && b == null) {
96
+
97
+ Lint at line 72 character 6: Extra comma.
98
+ },
99
+
100
+ checking public/javascripts/Marker.js... 1 error:
101
+
102
+ Lint at line 275 character 27: Missing radix parameter.
103
+ var x = parseInt(mapX);
104
+
105
+
106
+ Found 3 errors.
107
+ rake aborted!
108
+ JSLint test failed.
109
+
110
+ If you want to test specific file or files (just once, without modifying the config), you can pass paths to include
111
+ and/or paths to exclude to the rake task:
112
+
113
+ rake jslint paths=public/javascripts/models/*.js,public/javascripts/lib/*.js exclude_paths=public/javascripts/lib/jquery.js
114
+
115
+ For the best effect, you should include JSLint check in your Continuous Integration build - that way, you'll get
116
+ immediate notification when you've committed JS code with errors.
117
+
118
+
119
+ ## Additional options
120
+
121
+ I've added some additional options to JSLint to get rid of some warnings which I thought didn't make sense. They're all
122
+ disabled by default, but feel free to enable any or all of them if you feel abused by JSLint.
123
+
124
+ Here's a documentation for all the extra options:
125
+
126
+
127
+ ### lastsemic
128
+
129
+ If set to true, this will ignore warnings about missing semicolon after a statement, if the statement is the last one in
130
+ a block or function. I've added this because I like to omit the semicolon in one-liner anonymous functions, in
131
+ situations like this:
132
+
133
+ var ids = $$('.entry').map(function(e) { return e.id });
134
+
135
+
136
+ ### newstat
137
+
138
+ Allows you to use a call to 'new' as a whole statement, without assigning the result anywhere. Sometimes you want to
139
+ create an instance of a class, but you don't need to assign it anywhere - the call to constructor starts the action
140
+ automatically. This includes calls like `new Ajax.Request(...)` or `new Effect.Highlight(...)` used when working with
141
+ Prototype and Scriptaculous.
142
+
143
+
144
+ ### statinexp
145
+
146
+ JSLint has a warning that says "Expected an assignment or function call and instead saw an expression" - you get it
147
+ when you write an expression and you don't use it for anything, like if you wrote such line:
148
+
149
+ $$('.entry').length;
150
+
151
+ Just checking the length without assigning it anywhere or passing to any function doesn't make any sense, so it's good
152
+ that JSLint complains. However, there are some cases where the code makes perfect sense, but JSLint still thinks it
153
+ doesn't. Examples:
154
+
155
+ element && element.show(); // call show only if element is not null
156
+ selected ? element.show() : element.hide(); // more readable than if & else with brackets
157
+
158
+ So I've tweaked the code that creates this warning so that it doesn't print it if the code makes sense. Specifically:
159
+
160
+ * expressions joined with && or || are accepted if the last one in the line is a statement
161
+ * expressions with ?: are accepted if both alternatives (before and after the colon) are statements
162
+
163
+
164
+ ## Credits
165
+
166
+ * JSLint on Rails was created by [Jakub Suder](http://psionides.jogger.pl), licensed under MIT License
167
+ * JSLint was created by [Douglas Crockford](http://jslint.com)
@@ -0,0 +1,79 @@
1
+ # ------------ rake task options ------------
2
+
3
+ # JS files to check by default, if no parameters are passed to rake jslint
4
+ # (you may want to limit this only to your own scripts and exclude any external scripts and frameworks)
5
+
6
+ # this can be overridden by adding 'paths' and 'exclude_paths' parameter to rake command:
7
+ # rake jslint paths=path1,path2,... exclude_paths=library1,library2,...
8
+
9
+ paths:
10
+ - public/javascripts/**/*.js
11
+
12
+ exclude_paths:
13
+
14
+
15
+ # ------------ jslint options ------------
16
+ # see http://www.jslint.com/lint.html#options for more detailed explanations
17
+
18
+ # "enforce" type options (true means potentially more warnings)
19
+
20
+ adsafe: false # true if ADsafe rules should be enforced. See http://www.ADsafe.org/
21
+ bitwise: true # true if bitwise operators should not be allowed
22
+ newcap: true # true if Initial Caps must be used with constructor functions
23
+ eqeqeq: false # true if === should be required (for ALL equality comparisons)
24
+ immed: false # true if immediate function invocations must be wrapped in parens
25
+ nomen: false # true if initial or trailing underscore in identifiers should be forbidden
26
+ onevar: false # true if only one var statement per function should be allowed
27
+ plusplus: false # true if ++ and -- should not be allowed
28
+ regexp: false # true if . and [^...] should not be allowed in RegExp literals
29
+ safe: false # true if the safe subset rules are enforced (used by ADsafe)
30
+ strict: false # true if the ES5 "use strict"; pragma is required
31
+ undef: false # true if variables must be declared before used
32
+ white: false # true if strict whitespace rules apply (see also 'indent' option)
33
+
34
+ # "allow" type options (false means potentially more warnings)
35
+
36
+ cap: false # true if upper case HTML should be allowed
37
+ css: true # true if CSS workarounds should be tolerated
38
+ debug: false # true if debugger statements should be allowed (set to false before going into production)
39
+ evil: false # true if eval should be allowed
40
+ forin: true # true if unfiltered 'for in' statements should be allowed
41
+ fragment: true # true if HTML fragments should be allowed
42
+ laxbreak: false # true if statement breaks should not be checked
43
+ on: false # true if HTML event handlers (e.g. onclick="...") should be allowed
44
+ sub: false # true if subscript notation may be used for expressions better expressed in dot notation
45
+
46
+ # other options
47
+
48
+ maxlen: 120 # Maximum line length
49
+ indent: 2 # Number of spaces that should be used for indentation - used only if 'white' option is set
50
+ maxerr: 50 # The maximum number of warnings reported (per file)
51
+ passfail: false # true if the scan should stop on first error (per file)
52
+ # following are relevant only if undef = true
53
+ predef: '' # Names of predefined global variables - comma-separated string
54
+ browser: true # true if the standard browser globals should be predefined
55
+ rhino: false # true if the Rhino environment globals should be predefined
56
+ sidebar: false # true if the Windows Sidebar Gadgets globals should be predefined
57
+ widget: false # true if the Yahoo Widgets globals should be predefined
58
+ devel: true # true if functions like alert, confirm, console, prompt etc. are predefined
59
+
60
+
61
+ # ------------ jslint_on_rails custom lint options (switch to true to disable some annoying warnings) ------------
62
+
63
+ # ignores "missing semicolon" warning at the end of a function; this lets you write one-liners
64
+ # like: x.map(function(i) { return i + 1 }); without having to put a second semicolon inside the function
65
+ lastsemic: false
66
+
67
+ # allows you to use the 'new' expression as a statement (without assignment)
68
+ # so you can call e.g. new Ajax.Request(...), new Effect.Highlight(...) without assigning to a dummy variable
69
+ newstat: false
70
+
71
+ # ignores the "Expected an assignment or function call and instead saw an expression" warning,
72
+ # if the expression contains a proper statement and makes sense; this lets you write things like:
73
+ # element && element.show();
74
+ # valid || other || lastChance || alert('OMG!');
75
+ # selected ? show() : hide();
76
+ # although these will still cause a warning:
77
+ # element && link;
78
+ # selected ? 5 : 10;
79
+ statinexp: false
@@ -0,0 +1,3 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/jslint/errors')
2
+ require File.expand_path(File.dirname(__FILE__) + '/jslint/utils')
3
+ require File.expand_path(File.dirname(__FILE__) + '/jslint/lint')
@@ -0,0 +1,9 @@
1
+ module JSLint
2
+
3
+ class NoJavaException < StandardError
4
+ end
5
+
6
+ class LintCheckFailure < StandardError
7
+ end
8
+
9
+ end
@@ -0,0 +1,64 @@
1
+ module JSLint
2
+
3
+ PATH = File.dirname(__FILE__)
4
+
5
+ TEST_JAR_FILE = File.expand_path("#{PATH}/../../vendor/test.jar")
6
+ RHINO_JAR_FILE = File.expand_path("#{PATH}/../../vendor/rhino.jar")
7
+ TEST_JAR_CLASS = "Test"
8
+ RHINO_JAR_CLASS = "org.mozilla.javascript.tools.shell.Main"
9
+
10
+ JSLINT_FILE = File.expand_path("#{PATH}/../../vendor/jslint.js")
11
+
12
+ class Lint
13
+
14
+ # available options:
15
+ # :paths => [list of paths...]
16
+ # :exclude_paths => [list of exluded paths...]
17
+ # :config_path => path to custom config file (can be set via JSLint.config_path too)
18
+ def initialize(options = {})
19
+ default_config = Utils.load_config_file(DEFAULT_CONFIG_FILE)
20
+ custom_config = Utils.load_config_file(options[:config_path] || JSLint.config_path)
21
+ @config = default_config.merge(custom_config)
22
+
23
+ included_files = files_matching_paths(options, :paths)
24
+ excluded_files = files_matching_paths(options, :exclude_paths)
25
+ @file_list = Utils.exclude_files(included_files, excluded_files)
26
+
27
+ ['paths', 'exclude_paths', 'config_path'].each { |field| @config.delete(field) }
28
+ end
29
+
30
+ def run
31
+ check_java
32
+ puts "Running JSLint:\n\n"
33
+ command = "java -cp #{RHINO_JAR_FILE} #{RHINO_JAR_CLASS} #{JSLINT_FILE} #{option_string} #{@file_list.join(' ')}"
34
+ success = system(command)
35
+ raise LintCheckFailure, "JSLint test failed." unless success
36
+ end
37
+
38
+
39
+ private
40
+
41
+ def option_string
42
+ @config.map { |k, v| "#{k}=#{v.inspect}" }.join(',')
43
+ end
44
+
45
+ def check_java
46
+ unless @java_ok
47
+ java_test = %x(java -cp #{TEST_JAR_FILE} #{TEST_JAR_CLASS})
48
+ if java_test.strip == "OK"
49
+ @java_ok = true
50
+ else
51
+ raise NoJavaException, "Please install Java before running JSLint."
52
+ end
53
+ end
54
+ end
55
+
56
+ def files_matching_paths(options, field)
57
+ path_list = options[field] || @config[field.to_s] || []
58
+ file_list = path_list.map { |p| Dir[p] }.flatten
59
+ Utils.unique_files(file_list)
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,2 @@
1
+ # for Rails, set config file path to config/jslint.yml in Rails root
2
+ JSLint.config_path = File.expand_path(RAILS_ROOT + '/config/jslint.yml')
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../jslint')
2
+
3
+ desc "Run JSLint check on selected Javascript files"
4
+ task :jslint do
5
+ include_paths = JSLint::Utils.paths_from_command_line('paths')
6
+ exclude_paths = JSLint::Utils.paths_from_command_line('exclude_paths')
7
+
8
+ if include_paths && exclude_paths.nil?
9
+ # if you pass paths= on command line but not exclude_paths=, and you have exclude_paths
10
+ # set in the config file, then the old exclude pattern will be used against the new
11
+ # include pattern, which may be very confusing...
12
+ exclude_paths = []
13
+ end
14
+
15
+ lint = JSLint::Lint.new :paths => include_paths, :exclude_paths => exclude_paths
16
+ lint.run
17
+ end
18
+
19
+ namespace :jslint do
20
+
21
+ desc "Create a copy of the default JSLint config file in your config directory"
22
+ task :copy_config do
23
+ JSLint::Utils.copy_config_file
24
+ end
25
+
26
+ end
@@ -0,0 +1,70 @@
1
+ require 'ftools'
2
+
3
+ module JSLint
4
+
5
+ DEFAULT_CONFIG_FILE = File.expand_path(File.dirname(__FILE__) + "/../../config/jslint.yml")
6
+
7
+ class << self
8
+ attr_accessor :config_path
9
+ end
10
+
11
+ module Utils
12
+ class << self
13
+
14
+ def load_config_file(file_name)
15
+ if file_name && File.exists?(file_name) && File.file?(file_name) && File.readable?(file_name)
16
+ YAML.load_file(file_name)
17
+ else
18
+ {}
19
+ end
20
+ end
21
+
22
+ # workaround for a problem with case-insensitive file systems like HFS on Mac
23
+ def unique_files(list)
24
+ files = []
25
+ list.each do |entry|
26
+ files << entry unless files.any? { |f| File.identical?(f, entry) }
27
+ end
28
+ files
29
+ end
30
+
31
+ # workaround for a problem with case-insensitive file systems like HFS on Mac
32
+ def exclude_files(list, excluded)
33
+ list.reject { |entry| excluded.any? { |f| File.identical?(f, entry) }}
34
+ end
35
+
36
+ def paths_from_command_line(field)
37
+ argument = ENV[field] || ENV[field.upcase]
38
+ argument && argument.split(/,/)
39
+ end
40
+
41
+ def copy_config_file
42
+ raise ArgumentError, "Please set JSLint.config_path" if JSLint.config_path.nil?
43
+ print "Copying default config file to #{File.expand_path(JSLint.config_path)}... "
44
+ if File.exists?(JSLint.config_path)
45
+ puts "\n\nWarning: config file exists, so it won't be overwritten. " +
46
+ "You can copy it manually from the jslint_on_rails directory if you want to reset it."
47
+ else
48
+ File.copy(JSLint::DEFAULT_CONFIG_FILE, JSLint.config_path)
49
+ puts "OK."
50
+ end
51
+ end
52
+
53
+ def remove_config_file
54
+ raise ArgumentError, "Please set JSLint.config_path" if JSLint.config_path.nil?
55
+ print "Removing config file... "
56
+ if File.exists?(JSLint.config_path) && File.file?(JSLint.config_path)
57
+ if File.read(JSLint.config_path) == File.read(JSLint::DEFAULT_CONFIG_FILE)
58
+ File.delete(JSLint.config_path)
59
+ puts "OK."
60
+ else
61
+ puts "File was modified, so it won't be deleted automatically."
62
+ end
63
+ else
64
+ puts "OK (no config file found)."
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end