jshint_on_rails 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog.markdown +8 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +22 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +70 -0
- data/Rakefile +10 -0
- data/lib/jshint.rb +7 -0
- data/lib/jshint/config/jshint.yml +91 -0
- data/lib/jshint/errors.rb +9 -0
- data/lib/jshint/lint.rb +80 -0
- data/lib/jshint/rails.rb +4 -0
- data/lib/jshint/railtie.rb +21 -0
- data/lib/jshint/tasks.rb +27 -0
- data/lib/jshint/utils.rb +80 -0
- data/lib/jshint/vendor/jshint.js +6011 -0
- data/lib/jshint/vendor/rhino.jar +0 -0
- data/lib/jshint/vendor/test.jar +0 -0
- data/lib/jshint_on_rails.rb +1 -0
- data/spec/lint_spec.rb +179 -0
- data/spec/railtie_spec.rb +31 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/utils_spec.rb +148 -0
- metadata +88 -0
data/Changelog.markdown
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
fakefs (0.2.1)
|
6
|
+
rake (0.8.7)
|
7
|
+
rspec (2.1.0)
|
8
|
+
rspec-core (~> 2.1.0)
|
9
|
+
rspec-expectations (~> 2.1.0)
|
10
|
+
rspec-mocks (~> 2.1.0)
|
11
|
+
rspec-core (2.1.0)
|
12
|
+
rspec-expectations (2.1.0)
|
13
|
+
diff-lcs (~> 1.1.2)
|
14
|
+
rspec-mocks (2.1.0)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
fakefs
|
21
|
+
rake
|
22
|
+
rspec
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Bruno Gouveia
|
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.
|
data/README.markdown
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
##JSHint On Rails
|
2
|
+
JSHint on rails is a fork project from JSLint_on_rails, adapted to work with jshint.
|
3
|
+
|
4
|
+
**Installation Dependencies**
|
5
|
+
* Java 5 >
|
6
|
+
* Ruby 1.8 >
|
7
|
+
* Rails 2 >
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
**Rails 3**
|
12
|
+
* add `gem 'jshint_on_rails'` to you're projects Gemfile
|
13
|
+
|
14
|
+
The first time you run it, a file in config/jshint.yml will be created. It can be customized to fit your needs (well explained below).
|
15
|
+
|
16
|
+
As this project is a fork of psionides jslint_on_rails, the instructions are the same. [Click here](https://github.com/psionides/jslint_on_rails/blob/master/README.markdown) to follow his instructions.
|
17
|
+
|
18
|
+
## Configuration
|
19
|
+
|
20
|
+
After the installation, observe that you'll probably will need to customize some settings, for example, the files you want to test and the ones you want to ignore (ex.: libraries such as jquery, mootools, underscore, etc).
|
21
|
+
|
22
|
+
The default config allows you to:
|
23
|
+
* write single line conditional statements
|
24
|
+
* ignore whitespaces (to support the option above and still being indented)
|
25
|
+
|
26
|
+
## Running
|
27
|
+
|
28
|
+
To start checking your stuff run the following:
|
29
|
+
|
30
|
+
[bundle exec] rake jslint
|
31
|
+
|
32
|
+
Then you should see:
|
33
|
+
|
34
|
+
Running JSHint:
|
35
|
+
|
36
|
+
checking public/javascripts/scripts.js... OK
|
37
|
+
checking public/javascripts/models.js... OK
|
38
|
+
checking public/javascripts/presenters.js... OK
|
39
|
+
|
40
|
+
No JS errors found =)
|
41
|
+
|
42
|
+
If anything is wrong, you will get something like this instead:
|
43
|
+
|
44
|
+
Running JSHint:
|
45
|
+
|
46
|
+
checking public/javascripts/scripts.js... 2 errors:
|
47
|
+
|
48
|
+
Lint at line 24 character 15: Use '===' to compare with 'null'.
|
49
|
+
if (a == null && b == null) {
|
50
|
+
|
51
|
+
Lint at line 72 character 6: Extra comma.
|
52
|
+
},
|
53
|
+
|
54
|
+
|
55
|
+
Found 2 errors =(
|
56
|
+
rake aborted!
|
57
|
+
JSHint test failed.
|
58
|
+
|
59
|
+
|
60
|
+
If you want to test specific file or files (just once, without modifying the config), you can pass paths to include
|
61
|
+
and/or paths to exclude to the rake task:
|
62
|
+
|
63
|
+
rake jslint paths=public/javascripts/models/*.js,public/javascripts/lib/*.js exclude_paths=public/javascripts/lib/jquery.js
|
64
|
+
|
65
|
+
|
66
|
+
## Credits
|
67
|
+
|
68
|
+
* JSLint on Rails was created by [Jakub Suder](http://psionides.jogger.pl), licensed under MIT License
|
69
|
+
* JSHint is a fork of JSLint and is maintained by the [JSHint Community](https://github.com/jshint/jshint)
|
70
|
+
* JSLint was created by [Douglas Crockford](http://jslint.com)
|
data/Rakefile
ADDED
data/lib/jshint.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# ------------ rake task options ------------
|
2
|
+
|
3
|
+
# JS files to check by default, if no parameters are passed to rake jshint
|
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 jshint paths=path1,path2,... exclude_paths=library1,library2,...
|
8
|
+
|
9
|
+
paths:
|
10
|
+
- public/javascripts/**/*.js
|
11
|
+
|
12
|
+
exclude_paths:
|
13
|
+
|
14
|
+
|
15
|
+
# ------------ jshint options ------------
|
16
|
+
# visit http://jshint.com/ for complete documentation
|
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: true # 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: false # 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
|
+
es5: false # true if ECMAScript 5 syntax should be allowed
|
40
|
+
evil: false # true if eval should be allowed
|
41
|
+
forin: false # true if unfiltered 'for in' statements should be allowed
|
42
|
+
fragment: false # true if HTML fragments should be allowed
|
43
|
+
laxbreak: false # true if statement breaks should not be checked
|
44
|
+
on: false # true if HTML event handlers (e.g. onclick="...") should be allowed
|
45
|
+
sub: false # true if subscript notation may be used for expressions better expressed in dot notation
|
46
|
+
|
47
|
+
# other options
|
48
|
+
|
49
|
+
maxlen: 160 # Maximum line length
|
50
|
+
indent: 2 # Number of spaces that should be used for indentation - used only if 'white' option is set
|
51
|
+
maxerr: 50 # The maximum number of warnings reported (per file)
|
52
|
+
passfail: false # true if the scan should stop on first error (per file)
|
53
|
+
# following are relevant only if undef = true
|
54
|
+
predef: '' # Names of predefined global variables - comma-separated string or a YAML array
|
55
|
+
browser: true # true if the standard browser globals should be predefined
|
56
|
+
rhino: false # true if the Rhino environment globals should be predefined
|
57
|
+
windows: false # true if Windows-specific globals should be predefined
|
58
|
+
widget: false # true if the Yahoo Widgets globals should be predefined
|
59
|
+
devel: false # true if functions like alert, confirm, console, prompt etc. are predefined
|
60
|
+
|
61
|
+
# jshint options
|
62
|
+
loopfunc: true # true if functions should be allowed to be defined within loops
|
63
|
+
asi: true # true if automatic semicolon insertion should be tolerated
|
64
|
+
boss: true # true if advanced usage of assignments and == should be allowed
|
65
|
+
couch: true # true if CouchDB globals should be predefined
|
66
|
+
curly: false # true if curly braces around blocks should be required (even in if/for/while)
|
67
|
+
noarg: true # true if arguments.caller and arguments.callee should be disallowed
|
68
|
+
node: true # true if the Node.js environment globals should be predefined
|
69
|
+
noempty: true # true if empty blocks should be disallowed
|
70
|
+
nonew: true # true if using `new` for side-effects should be disallowed
|
71
|
+
|
72
|
+
|
73
|
+
# ------------ jshint_on_rails custom lint options (switch to true to disable some annoying warnings) ------------
|
74
|
+
|
75
|
+
# ignores "missing semicolon" warning at the end of a function; this lets you write one-liners
|
76
|
+
# like: x.map(function(i) { return i + 1 }); without having to put a second semicolon inside the function
|
77
|
+
lastsemic: false
|
78
|
+
|
79
|
+
# allows you to use the 'new' expression as a statement (without assignment)
|
80
|
+
# so you can call e.g. new Ajax.Request(...), new Effect.Highlight(...) without assigning to a dummy variable
|
81
|
+
newstat: false
|
82
|
+
|
83
|
+
# ignores the "Expected an assignment or function call and instead saw an expression" warning,
|
84
|
+
# if the expression contains a proper statement and makes sense; this lets you write things like:
|
85
|
+
# element && element.show();
|
86
|
+
# valid || other || lastChance || alert('OMG!');
|
87
|
+
# selected ? show() : hide();
|
88
|
+
# although these will still cause a warning:
|
89
|
+
# element && link;
|
90
|
+
# selected ? 5 : 10;
|
91
|
+
statinexp: false
|
data/lib/jshint/lint.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'jshint/errors'
|
2
|
+
require 'jshint/utils'
|
3
|
+
|
4
|
+
module JSHint
|
5
|
+
|
6
|
+
PATH = File.dirname(__FILE__)
|
7
|
+
|
8
|
+
TEST_JAR_FILE = File.expand_path("#{PATH}/vendor/test.jar")
|
9
|
+
RHINO_JAR_FILE = File.expand_path("#{PATH}/vendor/rhino.jar")
|
10
|
+
TEST_JAR_CLASS = "Test"
|
11
|
+
RHINO_JAR_CLASS = "org.mozilla.javascript.tools.shell.Main"
|
12
|
+
|
13
|
+
JSHINT_FILE = File.expand_path("#{PATH}/vendor/jshint.js")
|
14
|
+
|
15
|
+
class Lint
|
16
|
+
|
17
|
+
# available options:
|
18
|
+
# :paths => [list of paths...]
|
19
|
+
# :exclude_paths => [list of exluded paths...]
|
20
|
+
# :config_path => path to custom config file (can be set via JSHint.config_path too)
|
21
|
+
def initialize(options = {})
|
22
|
+
default_config = Utils.load_config_file(DEFAULT_CONFIG_FILE)
|
23
|
+
custom_config = Utils.load_config_file(options[:config_path] || JSHint.config_path)
|
24
|
+
@config = default_config.merge(custom_config)
|
25
|
+
|
26
|
+
if @config['predef'].is_a?(Array)
|
27
|
+
@config['predef'] = @config['predef'].join(",")
|
28
|
+
end
|
29
|
+
|
30
|
+
included_files = files_matching_paths(options, :paths)
|
31
|
+
excluded_files = files_matching_paths(options, :exclude_paths)
|
32
|
+
@file_list = Utils.exclude_files(included_files, excluded_files)
|
33
|
+
@file_list.delete_if { |f| File.size(f) == 0 }
|
34
|
+
|
35
|
+
['paths', 'exclude_paths'].each { |field| @config.delete(field) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def run
|
39
|
+
check_java
|
40
|
+
Utils.xputs "Running JSHint...\n\n"
|
41
|
+
arguments = "#{JSHINT_FILE} #{option_string.inspect.gsub(/\$/, "\\$")} #{@file_list.join(' ')}"
|
42
|
+
success = call_java_with_status(RHINO_JAR_FILE, RHINO_JAR_CLASS, arguments)
|
43
|
+
raise LintCheckFailure, "JSHint test failed." unless success
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def call_java_with_output(jar, mainClass, arguments = "")
|
49
|
+
%x(java -cp #{jar} #{mainClass} #{arguments})
|
50
|
+
end
|
51
|
+
|
52
|
+
def call_java_with_status(jar, mainClass, arguments = "")
|
53
|
+
system("java -cp #{jar} #{mainClass} #{arguments}")
|
54
|
+
end
|
55
|
+
|
56
|
+
def option_string
|
57
|
+
@config.map { |k, v| "#{k}=#{v.inspect}" }.join('&')
|
58
|
+
end
|
59
|
+
|
60
|
+
def check_java
|
61
|
+
unless @java_ok
|
62
|
+
java_test = call_java_with_output(TEST_JAR_FILE, TEST_JAR_CLASS)
|
63
|
+
if java_test.strip == "OK"
|
64
|
+
@java_ok = true
|
65
|
+
else
|
66
|
+
raise NoJavaException, "Please install Java before running JSHint."
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def files_matching_paths(options, field)
|
72
|
+
path_list = options[field] || @config[field.to_s] || []
|
73
|
+
path_list = [path_list] unless path_list.is_a?(Array)
|
74
|
+
file_list = path_list.map { |p| Dir[p] }.flatten
|
75
|
+
Utils.unique_files(file_list)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/lib/jshint/rails.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module JSHint
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
|
4
|
+
rake_tasks do
|
5
|
+
require 'jshint/rails'
|
6
|
+
require 'jshint/tasks'
|
7
|
+
JSHint::Railtie.create_example_config
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.create_example_config
|
11
|
+
unless File.exists?(JSHint.config_path)
|
12
|
+
begin
|
13
|
+
JSHint::Utils.copy_config_file
|
14
|
+
rescue StandardError => error
|
15
|
+
puts "Error: #{error.message}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/jshint/tasks.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'jshint/lint'
|
2
|
+
require 'jshint/utils'
|
3
|
+
|
4
|
+
desc "Run JSHint check on selected Javascript files"
|
5
|
+
task :jshint do
|
6
|
+
include_paths = JSHint::Utils.paths_from_command_line('paths')
|
7
|
+
exclude_paths = JSHint::Utils.paths_from_command_line('exclude_paths')
|
8
|
+
|
9
|
+
if include_paths && exclude_paths.nil?
|
10
|
+
# if you pass paths= on command line but not exclude_paths=, and you have exclude_paths
|
11
|
+
# set in the config file, then the old exclude pattern will be used against the new
|
12
|
+
# include pattern, which may be very confusing...
|
13
|
+
exclude_paths = []
|
14
|
+
end
|
15
|
+
|
16
|
+
lint = JSHint::Lint.new :paths => include_paths, :exclude_paths => exclude_paths
|
17
|
+
lint.run
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :jshint do
|
21
|
+
|
22
|
+
desc "Create a copy of the default JSHint config file in your config directory"
|
23
|
+
task :copy_config do
|
24
|
+
JSHint::Utils.copy_config_file
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/jshint/utils.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module JSHint
|
5
|
+
|
6
|
+
VERSION = "1.0.1"
|
7
|
+
DEFAULT_CONFIG_FILE = File.expand_path(File.dirname(__FILE__) + "/config/jshint.yml")
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_accessor :config_path
|
11
|
+
end
|
12
|
+
|
13
|
+
module Utils
|
14
|
+
class << self
|
15
|
+
|
16
|
+
def xprint(txt)
|
17
|
+
print txt
|
18
|
+
end
|
19
|
+
|
20
|
+
def xputs(txt)
|
21
|
+
puts txt
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_config_file(file_name)
|
25
|
+
if file_name && File.exists?(file_name) && File.file?(file_name) && File.readable?(file_name)
|
26
|
+
YAML.load_file(file_name)
|
27
|
+
else
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# workaround for a problem with case-insensitive file systems like HFS on Mac
|
33
|
+
def unique_files(list)
|
34
|
+
files = []
|
35
|
+
list.each do |entry|
|
36
|
+
files << entry unless files.any? { |f| File.identical?(f, entry) }
|
37
|
+
end
|
38
|
+
files
|
39
|
+
end
|
40
|
+
|
41
|
+
# workaround for a problem with case-insensitive file systems like HFS on Mac
|
42
|
+
def exclude_files(list, excluded)
|
43
|
+
list.reject { |entry| excluded.any? { |f| File.identical?(f, entry) }}
|
44
|
+
end
|
45
|
+
|
46
|
+
def paths_from_command_line(field)
|
47
|
+
argument = ENV[field] || ENV[field.upcase]
|
48
|
+
argument && argument.split(/,/)
|
49
|
+
end
|
50
|
+
|
51
|
+
def copy_config_file
|
52
|
+
raise ArgumentError, "Please set JSHint.config_path" if JSHint.config_path.nil?
|
53
|
+
xprint "Creating example JSHint config file in #{File.expand_path(JSHint.config_path)}... "
|
54
|
+
if File.exists?(JSHint.config_path)
|
55
|
+
xputs "\n\nWarning: config file exists, so it won't be overwritten. " +
|
56
|
+
"You can copy it manually from the jshint_on_rails directory if you want to reset it."
|
57
|
+
else
|
58
|
+
FileUtils.copy(JSHint::DEFAULT_CONFIG_FILE, JSHint.config_path)
|
59
|
+
xputs "done."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove_config_file
|
64
|
+
raise ArgumentError, "Please set JSHint.config_path" if JSHint.config_path.nil?
|
65
|
+
xprint "Removing config file... "
|
66
|
+
if File.exists?(JSHint.config_path) && File.file?(JSHint.config_path)
|
67
|
+
if File.read(JSHint.config_path) == File.read(JSHint::DEFAULT_CONFIG_FILE)
|
68
|
+
File.delete(JSHint.config_path)
|
69
|
+
xputs "OK."
|
70
|
+
else
|
71
|
+
xputs "File was modified, so it won't be deleted automatically."
|
72
|
+
end
|
73
|
+
else
|
74
|
+
xputs "OK (no config file found)."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|