jslint-v8 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+
2
+ module JSLintV8
3
+ class LintError
4
+ attr_reader :line_number, :character, :reason, :evidence
5
+
6
+ def initialize(jsobject)
7
+ @line_number = jsobject["line"]
8
+ @character = jsobject["character"]
9
+ @reason = jsobject["reason"]
10
+ @evidence = jsobject["evidence"]
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,79 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ module JSLintV8
5
+ class RakeTask < ::Rake::TaskLib
6
+ # name of the rake task
7
+ attr_accessor :name
8
+
9
+ # description for the task
10
+ attr_accessor :description
11
+
12
+ # inclusion glob pattern for files
13
+ attr_accessor :include_pattern
14
+
15
+ # exclusion glob pattern for files
16
+ attr_accessor :exclude_pattern
17
+
18
+ # output stream for this task
19
+ attr_accessor :output_stream
20
+
21
+ def initialize
22
+ # a default name
23
+ @name = "lint"
24
+
25
+ # a default description
26
+ @description = "Runs the JSLint Test Suite"
27
+
28
+ # by default a glob pattern that will include javascript files found in rails
29
+ @include_pattern = "app/javascripts/**/*.js"
30
+
31
+ # by default a glob pattern which will match no files
32
+ @exclude_pattern = ""
33
+
34
+ # by default use standard output for writing information
35
+ @output_stream = STDOUT
36
+
37
+ # if a block was given allow the block to call elements on this object
38
+ yield self if block_given?
39
+
40
+ # create the rake task
41
+ new_task = task(name) do
42
+ formatter = JSLintV8::Formatter.new(output_stream)
43
+
44
+ lint_result = runner.run do |file, errors|
45
+ formatter.tick(errors)
46
+ end
47
+
48
+ # put a separator line in between the ticks and any summary
49
+ output_stream.print "\n"
50
+
51
+ # print a summary of failed files
52
+ formatter.summary(files_to_run, lint_result)
53
+
54
+ # raise an exception if there are errors
55
+ raise "jslint suite failed" unless lint_result.empty?
56
+ end
57
+
58
+ # assign the description to the rake task
59
+ new_task.comment = description
60
+ end
61
+
62
+ #
63
+ # Returns a list of all files to run, sorted
64
+ #
65
+ def files_to_run
66
+ included_files = Dir.glob(include_pattern)
67
+ excluded_files = Dir.glob(exclude_pattern)
68
+
69
+ (included_files - excluded_files).sort
70
+ end
71
+
72
+ private
73
+
74
+ def runner
75
+ JSLintV8::Runner.new(files_to_run)
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,82 @@
1
+ require 'v8'
2
+
3
+ module JSLintV8
4
+ class Runner
5
+ JSLintLibraryFilename = File.expand_path("js/jslint.js", File.dirname(__FILE__))
6
+
7
+ attr_reader :file_list
8
+
9
+ def initialize(files)
10
+ if(files.is_a?(Array))
11
+ @file_list = files
12
+ else
13
+ @file_list = [files]
14
+ end
15
+ end
16
+
17
+ def run
18
+ # make sure all files exit
19
+ file_list.each do |file|
20
+ raise "file not found: #{file}" unless File.exist?(file)
21
+ end
22
+
23
+ result = {}
24
+
25
+ file_list.each do |file|
26
+ errors = jslint(File.read(file))
27
+
28
+ yield(file, errors) if block_given?
29
+
30
+ next if errors.empty?
31
+
32
+ result[file] = errors
33
+ end
34
+
35
+ result
36
+ end
37
+
38
+ def runtime
39
+ @runtime ||= lambda do
40
+ runtime = V8::Context.new
41
+
42
+ # load the jslint library into the runtime
43
+ runtime.eval(File.read JSLintLibraryFilename)
44
+
45
+ # return the runtime
46
+ runtime
47
+ end.call
48
+ end
49
+
50
+ def jslint(source_code)
51
+ jslint_function.call(source_code, jslint_options)
52
+ jslint_result
53
+ end
54
+
55
+ def jslint_function
56
+ runtime["JSLINT"];
57
+ end
58
+
59
+ def jslint_result
60
+ runtime["JSLINT"]["errors"].to_a.compact.map do |error_object|
61
+ JSLintV8::LintError.new(error_object)
62
+ end
63
+ end
64
+
65
+ def jslint_options
66
+ {
67
+ "bitwise" => true,
68
+ "eqeqeq" => true,
69
+ "immed" => true,
70
+ "newcap" => true,
71
+ "nomen" => true,
72
+ "onevar" => true,
73
+ "plusplus" => true,
74
+ "regexp" => true,
75
+ "rhino" => true,
76
+ "undef" => true,
77
+ "white" => true
78
+ }
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module JSLintV8
3
+ module Version
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ PATCH = 0
7
+ BUILD = nil
8
+
9
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
10
+ end
11
+ end
data/lib/jslint-v8.rb ADDED
@@ -0,0 +1,6 @@
1
+ module JSLintV8 end
2
+
3
+ require File.expand_path("jslint-v8/runner", File.dirname(__FILE__))
4
+ require File.expand_path("jslint-v8/rake_task", File.dirname(__FILE__))
5
+ require File.expand_path("jslint-v8/lint_error", File.dirname(__FILE__))
6
+ require File.expand_path("jslint-v8/formatter", File.dirname(__FILE__))
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "rubygems"
2
+ require 'test/unit'
3
+ require 'erb'
4
+
5
+ # require the library code
6
+ require File.expand_path("../lib/jslint-v8", File.dirname(__FILE__))
7
+
8
+ def erb_fixture(basename)
9
+ ::ERB.new(File.read(erb_filename(basename))).result
10
+ end
11
+
12
+ def erb_filename(basename)
13
+ File.expand_path("fixtures/#{basename}.txt.erb", File.dirname(__FILE__))
14
+ end
15
+
16
+ def js_filename(basename)
17
+ File.expand_path("fixtures/#{basename}.js", File.dirname(__FILE__))
18
+ end
data/test/suite.rb ADDED
@@ -0,0 +1,5 @@
1
+
2
+ # require all test cases
3
+ Dir.glob(File.join(File.dirname(__FILE__), "test_*.rb")).each do |test_file|
4
+ require test_file
5
+ end
data/test/test_cli.rb ADDED
@@ -0,0 +1,44 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'erb'
3
+
4
+ class TestCli < Test::Unit::TestCase
5
+ Executable = File.expand_path("../bin/jslint-v8", File.dirname(__FILE__))
6
+
7
+ def test_executable_exists
8
+ assert File.exist?(Executable)
9
+ end
10
+
11
+ def test_empty_args
12
+ result = `#{Executable}`
13
+
14
+ assert_equal "usage: jslint-v8 FILES\n", result
15
+ assert_equal false, $?.success?
16
+ end
17
+
18
+ def test_valid
19
+ result = %x{#{Executable} "#{js_filename "valid"}"}
20
+
21
+ assert $?.success?
22
+ assert_equal erb_fixture("cli-valid-expected-output"), result
23
+ end
24
+
25
+ def test_invalid
26
+ result = %x{#{Executable} "#{js_filename "invalid"}"}
27
+
28
+ assert_equal false, $?.success?
29
+ assert_equal erb_fixture("cli-invalid-expected-output"), result
30
+ end
31
+
32
+ def test_suite
33
+ defined_globals = js_filename("defined-globals")
34
+ defined_options = js_filename("defined-options")
35
+ invalid = js_filename("invalid")
36
+ valid = js_filename("valid")
37
+
38
+ result = %x{#{Executable} "#{defined_globals}" "#{defined_options}" "#{invalid}" "#{valid}"}
39
+
40
+ assert_equal false, $?.success?
41
+ assert_equal erb_fixture("cli-suite-expected-output"), result
42
+ end
43
+
44
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'erb'
3
+ require 'stringio'
4
+
5
+ class TestFormatter < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @output = String.new
9
+ @output_stream = StringIO.new(@output, "w+")
10
+
11
+ @formatter = JSLintV8::Formatter.new(@output_stream)
12
+ end
13
+
14
+ def test_create
15
+ assert_equal @output_stream.object_id, @formatter.output_stream.object_id
16
+ end
17
+
18
+ def test_tick
19
+ assert_equal "", @output
20
+
21
+ @formatter.tick([])
22
+
23
+ assert_equal ".", @output
24
+
25
+ @formatter.tick(["foo"])
26
+
27
+ assert_equal ".*", @output
28
+ end
29
+
30
+ def test_summary_with_no_errors
31
+ @formatter.summary(%w(foo bar), {})
32
+
33
+ assert_equal erb_fixture("formatter-summary-noerrors"), @output
34
+ end
35
+
36
+ def test_summary_with_errors
37
+ error_1 = JSLintV8::LintError.new("line" => 42, "character" => 10, "reason" => "because i can")
38
+ error_2 = JSLintV8::LintError.new("line" => 43, "character" => 3, "reason" => "a proof is not a proof")
39
+ error_3 = JSLintV8::LintError.new("line" => 139, "character" => 12, "reason" => "undefined global 'foo'")
40
+
41
+ result = {
42
+ "foo" => [error_1, error_2],
43
+ "bar" => [error_3]
44
+ }
45
+
46
+ @formatter.summary(%w(foo bar baz one two three), result)
47
+
48
+ assert_equal erb_fixture("formatter-summary-errors"), @output
49
+ end
50
+
51
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+
3
+ class TestLintError < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @object = {
7
+ "line" => 42,
8
+ "character" => 10,
9
+ "reason" => "because i can",
10
+ "evidence" => "I don't know, a proof is a proof. What kind of a proof? It's a proof. A proof is a proof, and when you have a good proof, it's because it's proven."
11
+ }
12
+
13
+ @error = JSLintV8::LintError.new(@object)
14
+ end
15
+
16
+ def test_line_number
17
+ assert_equal @error.line_number, 42
18
+ end
19
+
20
+ def test_character
21
+ assert_equal @error.character, 10
22
+ end
23
+
24
+ def test_reason
25
+ assert_equal @error.reason, "because i can"
26
+ end
27
+
28
+ def test_evidence
29
+ assert_equal @error.evidence, "I don't know, a proof is a proof. What kind of a proof? It's a proof. A proof is a proof, and when you have a good proof, it's because it's proven."
30
+ end
31
+
32
+ end
@@ -0,0 +1,141 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+
3
+ class TestRunner < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @runner = JSLintV8::Runner.new(%w(foo bar))
7
+ end
8
+
9
+ def test_lint_library_filename
10
+ assert File.exist? JSLintV8::Runner::JSLintLibraryFilename
11
+ end
12
+
13
+ def test_file_list
14
+ assert_equal @runner.file_list, %w(foo bar)
15
+ end
16
+
17
+ def test_constructor_enumerable_wrapping
18
+ @runner = JSLintV8::Runner.new("foo")
19
+
20
+ assert_equal @runner.file_list, %w(foo)
21
+ end
22
+
23
+ def test_file_not_found
24
+ assert_raise RuntimeError do
25
+ @runner.run
26
+ end
27
+ end
28
+
29
+ def test_file_found
30
+ filename = js_filename "valid"
31
+
32
+ assert_nothing_raised do
33
+ JSLintV8::Runner.new(filename).run
34
+ end
35
+ end
36
+
37
+ def test_runtime
38
+ assert @runner.runtime.is_a?(V8::Context)
39
+ end
40
+
41
+ def test_runtime_caching
42
+ first = @runner.runtime
43
+ assert_equal @runner.runtime.object_id, first.object_id
44
+ end
45
+
46
+ def test_jslint_function_proxy
47
+ assert_not_nil @runner.jslint_function
48
+ end
49
+
50
+ def test_jslint_result
51
+ assert @runner.jslint_result.is_a?(Array)
52
+ end
53
+
54
+ def test_jslint_default_options
55
+ assert @runner.jslint_options.keys.any?
56
+ end
57
+
58
+ def test_jslint_returns_array_of_errors
59
+ result = @runner.jslint("if(true) alert('foo');")
60
+
61
+ assert result.is_a?(Array)
62
+ assert result.length > 0
63
+ assert result.all? {|error| error.is_a?(JSLintV8::LintError) }
64
+ end
65
+
66
+ def test_run
67
+ filename = js_filename("invalid")
68
+
69
+ result = JSLintV8::Runner.new(filename).run
70
+
71
+ assert result.is_a?(Hash)
72
+ assert result.keys.include?(filename)
73
+ assert result[filename].is_a?(Array)
74
+ end
75
+
76
+ def test_valid_run
77
+ filename = js_filename("valid")
78
+
79
+ result = JSLintV8::Runner.new(filename).run
80
+
81
+ errors = result[filename]
82
+
83
+ assert errors.nil?
84
+ end
85
+
86
+ def test_invalid_run
87
+ filename = js_filename("invalid")
88
+
89
+ result = JSLintV8::Runner.new(filename).run
90
+
91
+ errors = result[filename]
92
+
93
+ assert errors.any?
94
+ end
95
+
96
+ def test_defined_globals
97
+ filename = js_filename("defined-globals")
98
+
99
+ result = JSLintV8::Runner.new(filename).run
100
+
101
+ errors = result[filename]
102
+
103
+ assert errors.nil?
104
+ end
105
+
106
+ def test_defined_options
107
+ filename = js_filename("defined-options")
108
+
109
+ result = JSLintV8::Runner.new(filename).run
110
+
111
+ errors = result[filename]
112
+
113
+ assert errors.nil?
114
+ end
115
+
116
+ def test_block
117
+ filename = js_filename("valid")
118
+
119
+ count = 0
120
+
121
+ JSLintV8::Runner.new(filename).run do |file, errors|
122
+ count += 1
123
+
124
+ if count == 1
125
+ assert_equal file, filename
126
+ assert_equal errors, []
127
+ end
128
+ end
129
+
130
+ assert_equal count, 1
131
+ end
132
+
133
+ def test_rejects_successful
134
+ valid_file = js_filename("valid")
135
+ invalid_file = js_filename("invalid")
136
+
137
+ result = JSLintV8::Runner.new([valid_file, invalid_file]).run
138
+
139
+ assert_equal result.keys.length, 1
140
+ end
141
+ end
data/test/test_task.rb ADDED
@@ -0,0 +1,126 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'rake'
3
+ require 'tempfile'
4
+
5
+ class TestTask < Test::Unit::TestCase
6
+
7
+ def setup
8
+ # completely reset the rake application to ensure everything is clean
9
+ Rake.application = nil
10
+ end
11
+
12
+ def test_creation
13
+ initial_length = Rake.application.tasks.length
14
+
15
+ JSLintV8::RakeTask.new
16
+
17
+ # the number of tasks should have increased by 1
18
+ assert_equal initial_length + 1, Rake.application.tasks.length
19
+ end
20
+
21
+ def test_default_name
22
+ JSLintV8::RakeTask.new
23
+
24
+ task = Rake.application.lookup("lint")
25
+
26
+ assert_equal "lint", task.name
27
+ end
28
+
29
+ def test_default_description
30
+ JSLintV8::RakeTask.new
31
+
32
+ task = Rake.application.lookup("lint")
33
+
34
+ assert_equal "Runs the JSLint Test Suite", task.comment
35
+ end
36
+
37
+ def test_default_include_pattern
38
+ task = JSLintV8::RakeTask.new
39
+
40
+ assert_equal "app/javascripts/**/*.js", task.include_pattern
41
+ end
42
+
43
+ def test_default_exclude_pattern
44
+ task = JSLintV8::RakeTask.new
45
+
46
+ assert_equal "", task.exclude_pattern
47
+ end
48
+
49
+ def test_default_output_stream
50
+ task = JSLintV8::RakeTask.new
51
+
52
+ assert_equal STDOUT, task.output_stream
53
+ end
54
+
55
+ def test_creation_block
56
+ tempfile = Tempfile.new("foo")
57
+
58
+ task = JSLintV8::RakeTask.new do |task|
59
+ task.name = "foo"
60
+ task.description = "Points out the bad codezzzz"
61
+ task.include_pattern = "js/**/*.js"
62
+ task.exclude_pattern = "js/**/*.txt"
63
+ task.output_stream = tempfile
64
+ end
65
+
66
+ rake_task = Rake.application.lookup("foo")
67
+
68
+ assert_equal "foo", rake_task.name
69
+ assert_equal "Points out the bad codezzzz", rake_task.comment
70
+ assert_equal "js/**/*.js", task.include_pattern
71
+ assert_equal "js/**/*.txt", task.exclude_pattern
72
+ assert_equal tempfile.object_id, task.output_stream.object_id
73
+ end
74
+
75
+ def test_files_to_run
76
+ task = JSLintV8::RakeTask.new do |task|
77
+ task.include_pattern = File.expand_path("fixtures/*", File.dirname(__FILE__))
78
+ task.exclude_pattern = File.expand_path("fixtures/*.erb", File.dirname(__FILE__))
79
+ end
80
+
81
+ expected_files = Dir.glob(File.expand_path("fixtures/*.js", File.dirname(__FILE__))).sort
82
+
83
+ assert_equal expected_files, task.files_to_run
84
+ end
85
+
86
+ def test_valid_output
87
+ result = String.new
88
+
89
+ task = JSLintV8::RakeTask.new do |task|
90
+ task.include_pattern = File.expand_path("fixtures/valid.js", File.dirname(__FILE__))
91
+ task.output_stream = StringIO.new(result, "w+")
92
+ end
93
+
94
+ Rake.application.lookup("lint").invoke
95
+
96
+ assert_equal erb_fixture("cli-valid-expected-output"), result
97
+ end
98
+
99
+ def test_invalid_output
100
+ result = String.new
101
+
102
+ task = JSLintV8::RakeTask.new do |task|
103
+ task.include_pattern = File.expand_path("fixtures/invalid.js", File.dirname(__FILE__))
104
+ task.output_stream = StringIO.new(result, "w+")
105
+ end
106
+
107
+ assert_raise RuntimeError do
108
+ Rake.application.lookup("lint").invoke
109
+ end
110
+
111
+ assert_equal erb_fixture("cli-invalid-expected-output"), result
112
+ end
113
+
114
+ def test_suite_output
115
+ result = String.new
116
+
117
+ task = JSLintV8::RakeTask.new do |task|
118
+ task.include_pattern = File.expand_path("fixtures/*.js", File.dirname(__FILE__))
119
+ task.output_stream = StringIO.new(result, "w+")
120
+ end
121
+
122
+ Rake.application.lookup("lint").invoke rescue # exception raised because of failing suite
123
+
124
+ assert_equal erb_fixture("cli-suite-expected-output"), result
125
+ end
126
+ end