coffeelint 0.0.6 → 0.1.2
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.
- checksums.yaml +7 -15
- data/.gitmodules +1 -1
- data/README.md +19 -7
- data/bin/coffeelint.rb +69 -11
- data/coffeelint/src/coffeelint.coffee +248 -31
- data/lib/coffeelint.rb +38 -18
- data/lib/coffeelint/version.rb +1 -1
- data/spec/coffeelint_spec.rb +11 -0
- metadata +46 -59
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
|
-
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
YjBmNzVkZjRmMGJlOTRhOWRjMzJjNTJjZWU4MTE4MWQ2ZWUxOGJiNTRkOGUw
|
10
|
-
MDdhODRmYjg3OGU0OTdmMWViYTg5ODEyOWExYTI3ZWUyMjY1YTBiMjk3N2Q0
|
11
|
-
MmViOWQzOTc5MTlkOTJhYzE2M2RmZTE1OGFmMGMzY2YwMWM1NWU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YmViOTViODYyOWMxNDg0YTVhZDAyNmRjMTkzZGI0NDY0ZDk5OGU1NDE4NTQ4
|
14
|
-
ZmExMWUyYTVkZDVjYmRiZGQ5OGM5MzFmOTkyODY5YzExYzA4NTMzMTcwZjNl
|
15
|
-
YTU3YjdhMjMxN2ExZThkNTY4NzhkMDc3MTRhYmUzNjE1NmY4OGY=
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bb1cdf1d80f8dca2f87ad8233000a3e659f9ad05
|
4
|
+
data.tar.gz: cfb06027c385cc3bbe4ab089a721eb6dbe1ac531
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 54efaacd4b1700ac6d88e18c03e75b1cc831abd1b43f1e65618644fd03a838a9e615f8344fb0b22147e01d5e3a717fbfe857085db1e96fc2a5cf423ce180cf36
|
7
|
+
data.tar.gz: 84854349a891d82f5acd8d1cc0582d758fd4857c60580ff2109246feab7fdc70fafa03875a6b18bb8095659887b74432ea97fca769489a024d875e336c86b7d5
|
data/.gitmodules
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Coffeelint
|
1
|
+
# Coffeelint [](http://badge.fury.io/rb/coffeelint)
|
2
2
|
|
3
3
|
Coffeelint is a set of simple ruby bindings for [coffeelint](https://github.com/clutchski/coffeelint).
|
4
4
|
|
@@ -25,18 +25,29 @@ Or install it yourself as:
|
|
25
25
|
There are a few different uses of coffeelint.
|
26
26
|
|
27
27
|
```ruby
|
28
|
-
lint_report = Coffeelint.lint(coffeescript source code)
|
29
|
-
lint_report = Coffeelint.lint_file(filename of coffeescript source)
|
30
|
-
lint_reports = Coffeelint.lint_dir(directory)
|
31
|
-
Coffeelint.lint_dir(directory) do |filename, lint_report|
|
28
|
+
lint_report = Coffeelint.lint(coffeescript source code, [config options])
|
29
|
+
lint_report = Coffeelint.lint_file(filename of coffeescript source, [config_options])
|
30
|
+
lint_reports = Coffeelint.lint_dir(directory, [config_options])
|
31
|
+
Coffeelint.lint_dir(directory, [config_options]) do |filename, lint_report|
|
32
32
|
puts filename
|
33
33
|
puts lint_report
|
34
34
|
Coffeelint.display_test_results(filename, lint_report)
|
35
35
|
end
|
36
|
-
Coffeelint.run_test(filename of coffeescript source) # Run tests and print pretty results (return true/false)
|
37
|
-
Coffeelint.run_test_suite(directory) # Runs a pretty report recursively for a directory (return true/false)
|
36
|
+
Coffeelint.run_test(filename of coffeescript source, [config_options]) # Run tests and print pretty results (return true/false)
|
37
|
+
Coffeelint.run_test_suite(directory, [config_options]) # Runs a pretty report recursively for a directory (return true/false)
|
38
38
|
```
|
39
39
|
|
40
|
+
### Config Options
|
41
|
+
|
42
|
+
The coffeelint gem takes the same config options as coffeelint. The only
|
43
|
+
addition is the config_file parameter. If you call coffeelint like:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
Coffeelint.run_test_suite(directory, :config_file => 'coffeelint_config.json')
|
47
|
+
```
|
48
|
+
|
49
|
+
Then it will load the config options from that file.
|
50
|
+
|
40
51
|
Additionally, if you are using rails you also get the rake task:
|
41
52
|
|
42
53
|
rake coffeelint
|
@@ -47,6 +58,7 @@ Finally, there is a command line utility that allows you to run standalone tests
|
|
47
58
|
|
48
59
|
coffeelint.rb <filename>
|
49
60
|
coffeelint.rb -r <directory>
|
61
|
+
coffeelint.rb -f <config.json> [-r] <fname-or-directory>
|
50
62
|
|
51
63
|
## Contributing
|
52
64
|
|
data/bin/coffeelint.rb
CHANGED
@@ -1,21 +1,79 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'coffeelint'
|
4
|
+
require 'coffeelint/version'
|
4
5
|
require 'optparse'
|
5
6
|
|
6
|
-
options = {
|
7
|
-
|
8
|
-
|
7
|
+
options = {
|
8
|
+
:recursive => false,
|
9
|
+
:noconfig => false,
|
10
|
+
:stdin => false,
|
11
|
+
:quiet => false,
|
12
|
+
}
|
9
13
|
|
10
|
-
|
11
|
-
|
14
|
+
linter_options = {}
|
15
|
+
|
16
|
+
opt_parser = OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: coffeelint.rb [options] source [...]"
|
18
|
+
|
19
|
+
=begin
|
20
|
+
-f, --file Specify a custom configuration file.
|
21
|
+
--noconfig Ignores the environment variable COFFEELINT_CONFIG. [boolean]
|
22
|
+
-h, --help Print help information.
|
23
|
+
-v, --version Print current version number.
|
24
|
+
-r Recursively lint .coffee files in subdirectories. [boolean]
|
25
|
+
--csv Use the csv reporter. [boolean]
|
26
|
+
--jslint Use the JSLint XML reporter. [boolean]
|
27
|
+
--nocolor Don't colorize the output [boolean]
|
28
|
+
-s, --stdin Lint the source from stdin [boolean]
|
29
|
+
-q, --quiet Only print errors. [boolean]
|
30
|
+
=end
|
31
|
+
|
32
|
+
|
33
|
+
opts.on "-f", "--file", "Specify a custom configuration file." do |f|
|
34
|
+
linter_options[:config_file] = f
|
35
|
+
end
|
36
|
+
|
37
|
+
=begin
|
38
|
+
opts.on "--noconfig", "Ignores the environment variabel COFFEELINT_CONFIG." do |f|
|
39
|
+
options[:noconfig] = true
|
40
|
+
end
|
41
|
+
=end
|
42
|
+
|
43
|
+
opts.on_tail "-h", "--help", "Print help information." do
|
44
|
+
puts opts
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on_tail "-v", "--version", "Print current version number." do
|
49
|
+
puts Coffeelint::VERSION
|
50
|
+
exit
|
12
51
|
end
|
13
|
-
end.parse!
|
14
52
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
53
|
+
opts.on '-r', "Recursively lint .coffee files in subdirectories." do
|
54
|
+
options[:recursive] = true
|
55
|
+
end
|
56
|
+
|
57
|
+
=begin
|
58
|
+
opts.on '-s', '--stdin', "Lint the source from stdin" do
|
59
|
+
options[:stdin] = true
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on '-q', '--quiet', 'Only print errors.' do
|
63
|
+
options[:quiet] = true
|
64
|
+
end
|
65
|
+
=end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
opt_parser.parse!
|
70
|
+
|
71
|
+
if ARGV.length > 0
|
72
|
+
ARGV.each do |file|
|
73
|
+
if options[:recursive]
|
74
|
+
Coffeelint.run_test_suite(file, linter_options)
|
75
|
+
else
|
76
|
+
Coffeelint.run_test(file, linter_options)
|
77
|
+
end
|
20
78
|
end
|
21
79
|
end
|
@@ -23,7 +23,7 @@ else
|
|
23
23
|
|
24
24
|
|
25
25
|
# The current version of Coffeelint.
|
26
|
-
coffeelint.VERSION = "0.5.
|
26
|
+
coffeelint.VERSION = "0.5.7"
|
27
27
|
|
28
28
|
|
29
29
|
# CoffeeLint error levels.
|
@@ -38,41 +38,144 @@ coffeelint.RULES = RULES =
|
|
38
38
|
no_tabs :
|
39
39
|
level : ERROR
|
40
40
|
message : 'Line contains tab indentation'
|
41
|
+
description: """
|
42
|
+
This rule forbids tabs in indentation. Enough said. It is enabled by
|
43
|
+
default.
|
44
|
+
"""
|
41
45
|
|
42
46
|
no_trailing_whitespace :
|
43
47
|
level : ERROR
|
44
48
|
message : 'Line ends with trailing whitespace'
|
45
49
|
allowed_in_comments : false
|
50
|
+
description: """
|
51
|
+
This rule forbids trailing whitespace in your code, since it is
|
52
|
+
needless cruft. It is enabled by default.
|
53
|
+
"""
|
46
54
|
|
47
55
|
max_line_length :
|
48
56
|
value: 80
|
49
57
|
level : ERROR
|
50
58
|
message : 'Line exceeds maximum allowed length'
|
59
|
+
description: """
|
60
|
+
This rule imposes a maximum line length on your code. <a
|
61
|
+
href="http://www.python.org/dev/peps/pep-0008/">Python's style
|
62
|
+
guide</a> does a good job explaining why you might want to limit the
|
63
|
+
length of your lines, though this is a matter of taste.
|
64
|
+
|
65
|
+
Lines can be no longer than eighty characters by default.
|
66
|
+
"""
|
51
67
|
|
52
68
|
camel_case_classes :
|
53
69
|
level : ERROR
|
54
70
|
message : 'Class names should be camel cased'
|
55
|
-
|
71
|
+
description: """
|
72
|
+
This rule mandates that all class names are camel cased. Camel
|
73
|
+
casing class names is a generally accepted way of distinguishing
|
74
|
+
constructor functions - which require the 'new' prefix to behave
|
75
|
+
properly - from plain old functions.
|
76
|
+
<pre>
|
77
|
+
<code># Good!
|
78
|
+
class BoaConstrictor
|
79
|
+
|
80
|
+
# Bad!
|
81
|
+
class boaConstrictor
|
82
|
+
</code>
|
83
|
+
</pre>
|
84
|
+
This rule is enabled by default.
|
85
|
+
"""
|
56
86
|
indentation :
|
57
87
|
value : 2
|
58
88
|
level : ERROR
|
59
89
|
message : 'Line contains inconsistent indentation'
|
90
|
+
description: """
|
91
|
+
This rule imposes a standard number of spaces to be used for
|
92
|
+
indentation. Since whitespace is significant in CoffeeScript, it's
|
93
|
+
critical that a project chooses a standard indentation format and
|
94
|
+
stays consistent. Other roads lead to darkness. <pre> <code>#
|
95
|
+
Enabling this option will prevent this ugly
|
96
|
+
# but otherwise valid CoffeeScript.
|
97
|
+
twoSpaces = () ->
|
98
|
+
fourSpaces = () ->
|
99
|
+
eightSpaces = () ->
|
100
|
+
'this is valid CoffeeScript'
|
101
|
+
|
102
|
+
</code>
|
103
|
+
</pre>
|
104
|
+
Two space indentation is enabled by default.
|
105
|
+
"""
|
60
106
|
|
61
107
|
no_implicit_braces :
|
62
108
|
level : IGNORE
|
63
109
|
message : 'Implicit braces are forbidden'
|
110
|
+
description: """
|
111
|
+
This rule prohibits implicit braces when declaring object literals.
|
112
|
+
Implicit braces can make code more difficult to understand,
|
113
|
+
especially when used in combination with optional parenthesis.
|
114
|
+
<pre>
|
115
|
+
<code># Do you find this code ambiguous? Is it a
|
116
|
+
# function call with three arguments or four?
|
117
|
+
myFunction a, b, 1:2, 3:4
|
118
|
+
|
119
|
+
# While the same code written in a more
|
120
|
+
# explicit manner has no ambiguity.
|
121
|
+
myFunction(a, b, {1:2, 3:4})
|
122
|
+
</code>
|
123
|
+
</pre>
|
124
|
+
Implicit braces are permitted by default, since their use is
|
125
|
+
idiomatic CoffeeScript.
|
126
|
+
"""
|
64
127
|
|
65
128
|
no_trailing_semicolons:
|
66
129
|
level : ERROR
|
67
130
|
message : 'Line contains a trailing semicolon'
|
131
|
+
description: """
|
132
|
+
This rule prohibits trailing semicolons, since they are needless
|
133
|
+
cruft in CoffeeScript.
|
134
|
+
<pre>
|
135
|
+
<code># This semicolon is meaningful.
|
136
|
+
x = '1234'; console.log(x)
|
137
|
+
|
138
|
+
# This semicolon is redundant.
|
139
|
+
alert('end of line');
|
140
|
+
</code>
|
141
|
+
</pre>
|
142
|
+
Trailing semicolons are forbidden by default.
|
143
|
+
"""
|
68
144
|
|
69
145
|
no_plusplus:
|
70
146
|
level : IGNORE
|
71
147
|
message : 'The increment and decrement operators are forbidden'
|
148
|
+
description: """
|
149
|
+
This rule forbids the increment and decrement arithmetic operators.
|
150
|
+
Some people believe the <tt>++</tt> and <tt>--</tt> to be cryptic
|
151
|
+
and the cause of bugs due to misunderstandings of their precedence
|
152
|
+
rules.
|
153
|
+
This rule is disabled by default.
|
154
|
+
"""
|
72
155
|
|
73
156
|
no_throwing_strings:
|
74
157
|
level : ERROR
|
75
158
|
message : 'Throwing strings is forbidden'
|
159
|
+
description: """
|
160
|
+
This rule forbids throwing string literals or interpolations. While
|
161
|
+
JavaScript (and CoffeeScript by extension) allow any expression to
|
162
|
+
be thrown, it is best to only throw <a
|
163
|
+
href="https://developer.mozilla.org
|
164
|
+
/en/JavaScript/Reference/Global_Objects/Error"> Error</a> objects,
|
165
|
+
because they contain valuable debugging information like the stack
|
166
|
+
trace. Because of JavaScript's dynamic nature, CoffeeLint cannot
|
167
|
+
ensure you are always throwing instances of <tt>Error</tt>. It will
|
168
|
+
only catch the simple but real case of throwing literal strings.
|
169
|
+
<pre>
|
170
|
+
<code># CoffeeLint will catch this:
|
171
|
+
throw "i made a boo boo"
|
172
|
+
|
173
|
+
# ... but not this:
|
174
|
+
throw getSomeString()
|
175
|
+
</code>
|
176
|
+
</pre>
|
177
|
+
This rule is enabled by default.
|
178
|
+
"""
|
76
179
|
|
77
180
|
cyclomatic_complexity:
|
78
181
|
value : 10
|
@@ -82,15 +185,39 @@ coffeelint.RULES = RULES =
|
|
82
185
|
no_backticks:
|
83
186
|
level : ERROR
|
84
187
|
message : 'Backticks are forbidden'
|
188
|
+
description: """
|
189
|
+
Backticks allow snippets of JavaScript to be embedded in
|
190
|
+
CoffeeScript. While some folks consider backticks useful in a few
|
191
|
+
niche circumstances, they should be avoided because so none of
|
192
|
+
JavaScript's "bad parts", like <tt>with</tt> and <tt>eval</tt>,
|
193
|
+
sneak into CoffeeScript.
|
194
|
+
This rule is enabled by default.
|
195
|
+
"""
|
85
196
|
|
86
197
|
line_endings:
|
87
198
|
level : IGNORE
|
88
199
|
value : 'unix' # or 'windows'
|
89
200
|
message : 'Line contains incorrect line endings'
|
90
|
-
|
201
|
+
description: """
|
202
|
+
This rule ensures your project uses only <tt>windows</tt> or
|
203
|
+
<tt>unix</tt> line endings. This rule is disabled by default.
|
204
|
+
"""
|
91
205
|
no_implicit_parens :
|
92
206
|
level : IGNORE
|
93
207
|
message : 'Implicit parens are forbidden'
|
208
|
+
description: """
|
209
|
+
This rule prohibits implicit parens on function calls.
|
210
|
+
<pre>
|
211
|
+
<code># Some folks don't like this style of coding.
|
212
|
+
myFunction a, b, c
|
213
|
+
|
214
|
+
# And would rather it always be written like this:
|
215
|
+
myFunction(a, b, c)
|
216
|
+
</code>
|
217
|
+
</pre>
|
218
|
+
Implicit parens are permitted by default, since their use is
|
219
|
+
idiomatic CoffeeScript.
|
220
|
+
"""
|
94
221
|
|
95
222
|
empty_constructor_needs_parens :
|
96
223
|
level : IGNORE
|
@@ -103,6 +230,19 @@ coffeelint.RULES = RULES =
|
|
103
230
|
no_empty_param_list :
|
104
231
|
level : IGNORE
|
105
232
|
message : 'Empty parameter list is forbidden'
|
233
|
+
description: """
|
234
|
+
This rule prohibits empty parameter lists in function definitions.
|
235
|
+
<pre>
|
236
|
+
<code># The empty parameter list in here is unnecessary:
|
237
|
+
myFunction = () ->
|
238
|
+
|
239
|
+
# We might favor this instead:
|
240
|
+
myFunction = ->
|
241
|
+
</code>
|
242
|
+
</pre>
|
243
|
+
Empty parameter lists are permitted by default.
|
244
|
+
"""
|
245
|
+
|
106
246
|
|
107
247
|
space_operators :
|
108
248
|
level : IGNORE
|
@@ -124,10 +264,33 @@ coffeelint.RULES = RULES =
|
|
124
264
|
no_stand_alone_at :
|
125
265
|
level : IGNORE
|
126
266
|
message : '@ must not be used stand alone'
|
267
|
+
description: """
|
268
|
+
This rule checks that no stand alone @ are in use, they are
|
269
|
+
discouraged. Further information in CoffeScript issue <a
|
270
|
+
href="https://github.com/jashkenas/coffee-script/issues/1601">
|
271
|
+
#1601</a>
|
272
|
+
"""
|
127
273
|
|
128
274
|
arrow_spacing :
|
129
275
|
level : IGNORE
|
130
276
|
message : 'Function arrow (->) must be spaced properly'
|
277
|
+
description: """
|
278
|
+
<p>This rule checks to see that there is spacing before and after
|
279
|
+
the arrow operator that declares a function. This rule is disabled
|
280
|
+
by default.</p> <p>Note that if arrow_spacing is enabled, and you
|
281
|
+
pass an empty function as a parameter, arrow_spacing will accept
|
282
|
+
either a space or no space in-between the arrow operator and the
|
283
|
+
parenthesis</p>
|
284
|
+
<pre><code># Both of this will not trigger an error,
|
285
|
+
# even with arrow_spacing enabled.
|
286
|
+
x(-> 3)
|
287
|
+
x( -> 3)
|
288
|
+
|
289
|
+
# However, this will trigger an error
|
290
|
+
x((a,b)-> 3)
|
291
|
+
</code>
|
292
|
+
</pre>
|
293
|
+
"""
|
131
294
|
|
132
295
|
coffeescript_error :
|
133
296
|
level : ERROR
|
@@ -265,8 +428,10 @@ class LineLinter
|
|
265
428
|
checkLineLength : () ->
|
266
429
|
rule = 'max_line_length'
|
267
430
|
max = @config[rule]?.value
|
268
|
-
if max and max < @line.length
|
269
|
-
|
431
|
+
if max and max < @line.length and not regexes.longUrlComment.test(@line)
|
432
|
+
attrs =
|
433
|
+
context: "Length is #{@line.length}, max is #{max}"
|
434
|
+
@createLineError(rule, attrs)
|
270
435
|
else
|
271
436
|
null
|
272
437
|
|
@@ -378,8 +543,7 @@ class LineLinter
|
|
378
543
|
null
|
379
544
|
|
380
545
|
#
|
381
|
-
# A class that performs checks on the output of CoffeeScript's
|
382
|
-
# lexer.
|
546
|
+
# A class that performs checks on the output of CoffeeScript's lexer.
|
383
547
|
#
|
384
548
|
class LexicalLinter
|
385
549
|
|
@@ -405,8 +569,7 @@ class LexicalLinter
|
|
405
569
|
errors.push(error) if error
|
406
570
|
errors
|
407
571
|
|
408
|
-
# Return an error if the given token fails a lint check, false
|
409
|
-
# otherwise.
|
572
|
+
# Return an error if the given token fails a lint check, false otherwise.
|
410
573
|
lintToken : (token) ->
|
411
574
|
[type, value, lineNumber] = token
|
412
575
|
|
@@ -437,17 +600,26 @@ class LexicalLinter
|
|
437
600
|
when "PARAM_START" then @lintParam(token)
|
438
601
|
when "@" then @lintStandaloneAt(token)
|
439
602
|
when "+", "-" then @lintPlus(token)
|
440
|
-
when "=", "MATH", "COMPARE", "LOGIC"
|
603
|
+
when "=", "MATH", "COMPARE", "LOGIC", "COMPOUND_ASSIGN"
|
441
604
|
@lintMath(token)
|
442
605
|
else null
|
443
606
|
|
444
607
|
lintUnary: (token) ->
|
445
608
|
if token[1] is 'new'
|
446
|
-
|
609
|
+
# Find the last chained identifier, e.g. Bar in new foo.bar.Bar().
|
610
|
+
identifierIndex = 1
|
611
|
+
loop
|
612
|
+
expectedIdentifier = @peek(identifierIndex)
|
613
|
+
expectedCallStart = @peek(identifierIndex + 1)
|
614
|
+
if expectedIdentifier?[0] is 'IDENTIFIER'
|
615
|
+
if expectedCallStart?[0] is '.'
|
616
|
+
identifierIndex += 2
|
617
|
+
continue
|
618
|
+
break
|
619
|
+
|
447
620
|
# The callStart is generated if your parameters are all on the same
|
448
621
|
# line with implicit parens, and if your parameters start on the
|
449
622
|
# next line, but is missing if there are no params and no parens.
|
450
|
-
expectedCallStart = @peek(2)
|
451
623
|
if expectedIdentifier?[0] is 'IDENTIFIER' and expectedCallStart?
|
452
624
|
if expectedCallStart[0] is 'CALL_START'
|
453
625
|
if expectedCallStart.generated
|
@@ -500,7 +672,8 @@ class LexicalLinter
|
|
500
672
|
p = @peek(-1)
|
501
673
|
unaries = ['TERMINATOR', '(', '=', '-', '+', ',', 'CALL_START',
|
502
674
|
'INDEX_START', '..', '...', 'COMPARE', 'IF',
|
503
|
-
'THROW', 'LOGIC', 'POST_IF', ':', '[', 'INDENT'
|
675
|
+
'THROW', 'LOGIC', 'POST_IF', ':', '[', 'INDENT',
|
676
|
+
'COMPOUND_ASSIGN', 'RETURN', 'MATH']
|
504
677
|
isUnary = if not p then false else p[0] in unaries
|
505
678
|
if (isUnary and token.spaced) or
|
506
679
|
(not isUnary and not token.spaced and not token.newLine)
|
@@ -602,7 +775,16 @@ class LexicalLinter
|
|
602
775
|
isIndexStart = nextToken[0] == 'INDEX_START'
|
603
776
|
isDot = nextToken[0] == '.'
|
604
777
|
|
605
|
-
|
778
|
+
# https://github.com/jashkenas/coffee-script/issues/1601
|
779
|
+
# @::foo is valid, but @:: behaves inconsistently and is planned for
|
780
|
+
# removal. Technically @:: is a stand alone ::, but I think it makes
|
781
|
+
# sense to group it into no_stand_alone_at
|
782
|
+
if nextToken[0] == '::'
|
783
|
+
protoProperty = @peek(2)
|
784
|
+
isValidProtoProperty = protoProperty[0] == 'IDENTIFIER'
|
785
|
+
|
786
|
+
if spaced or (not isIdentifier and not isIndexStart and
|
787
|
+
not isDot and not isValidProtoProperty)
|
606
788
|
@createLexError('no_stand_alone_at')
|
607
789
|
|
608
790
|
|
@@ -640,9 +822,13 @@ class LexicalLinter
|
|
640
822
|
# lines, which can be ignored.
|
641
823
|
if @isChainedCall()
|
642
824
|
currentLine = @lines[@lineNumber]
|
643
|
-
|
644
|
-
previousIndentation = previousLine.match(/^(\s*)/)[1].length
|
825
|
+
prevNum = 1
|
645
826
|
|
827
|
+
# keep going back until we are not at a comment or a blank line
|
828
|
+
prevNum += 1 while (/^\s*(#|$)/.test(@lines[@lineNumber - prevNum]))
|
829
|
+
previousLine = @lines[@lineNumber - prevNum]
|
830
|
+
|
831
|
+
previousIndentation = previousLine.match(/^(\s*)/)[1].length
|
646
832
|
# I don't know why, but when inside a function, you make a chained
|
647
833
|
# call and define an inline callback as a parameter, the body of
|
648
834
|
# that callback gets the indentation reported higher than it really
|
@@ -691,7 +877,7 @@ class LexicalLinter
|
|
691
877
|
|
692
878
|
lintArrowSpacing : (token) ->
|
693
879
|
# Throw error unless the following happens.
|
694
|
-
|
880
|
+
#
|
695
881
|
# We will take a look at the previous token to see
|
696
882
|
# 1. That the token is properly spaced
|
697
883
|
# 2. Wasn't generated by the CoffeeScript compiler
|
@@ -699,13 +885,19 @@ class LexicalLinter
|
|
699
885
|
# 4. If the function declaration has no parameters
|
700
886
|
# e.g. x(-> 3)
|
701
887
|
# x( -> 3)
|
888
|
+
#
|
889
|
+
# or a statement is wrapped in parentheses
|
890
|
+
# e.g. (-> true)()
|
891
|
+
#
|
702
892
|
# we will accept either having a space or not having a space there.
|
893
|
+
|
894
|
+
pp = @peek(-1)
|
703
895
|
unless (token.spaced? or token.newLine?) and
|
704
896
|
# Throw error unless the previous token...
|
705
|
-
(
|
706
|
-
|
707
|
-
|
708
|
-
(
|
897
|
+
((pp.spaced? or pp[0] is 'TERMINATOR') or #1
|
898
|
+
pp.generated? or #2
|
899
|
+
pp[0] is "INDENT" or #3
|
900
|
+
(pp[1] is "(" and not pp.generated?)) #4
|
709
901
|
@createLexError('arrow_spacing')
|
710
902
|
else
|
711
903
|
null
|
@@ -763,10 +955,8 @@ class ASTLinter
|
|
763
955
|
@lintNode(@node)
|
764
956
|
@errors
|
765
957
|
|
766
|
-
#
|
767
|
-
|
768
|
-
|
769
|
-
# Get the complexity of the current node.
|
958
|
+
# returns the "complexity" value of the current node.
|
959
|
+
getComplexity : (node) ->
|
770
960
|
name = node.constructor.name
|
771
961
|
complexity = if name in ['If', 'While', 'For', 'Try']
|
772
962
|
1
|
@@ -776,21 +966,30 @@ class ASTLinter
|
|
776
966
|
node.cases.length
|
777
967
|
else
|
778
968
|
0
|
969
|
+
return complexity
|
970
|
+
|
971
|
+
# Lint the AST node and return it's cyclomatic complexity.
|
972
|
+
lintNode : (node, line) ->
|
973
|
+
|
974
|
+
# Get the complexity of the current node.
|
975
|
+
name = node.constructor.name
|
976
|
+
complexity = @getComplexity(node)
|
779
977
|
|
780
978
|
# Add the complexity of all child's nodes to this one.
|
781
979
|
node.eachChild (childNode) =>
|
782
|
-
|
783
|
-
complexity += @lintNode(childNode)
|
784
|
-
return true
|
980
|
+
nodeLine = childNode.locationData.first_line
|
981
|
+
complexity += @lintNode(childNode, nodeLine) if childNode
|
785
982
|
|
786
983
|
# If the current node is a function, and it's over our limit, add an
|
787
984
|
# error to the list.
|
788
985
|
rule = @config.cyclomatic_complexity
|
986
|
+
|
789
987
|
if name == 'Code' and complexity >= rule.value
|
790
988
|
attrs = {
|
791
989
|
context: complexity + 1
|
792
990
|
level: rule.level
|
793
|
-
|
991
|
+
lineNumber: line + 1
|
992
|
+
lineNumberEnd: node.locationData.last_line + 1
|
794
993
|
}
|
795
994
|
error = createError 'cyclomatic_complexity', attrs
|
796
995
|
@errors.push error if error
|
@@ -826,6 +1025,22 @@ mergeDefaultConfig = (userConfig) ->
|
|
826
1025
|
config[rule] = defaults(userConfig[rule], ruleConfig)
|
827
1026
|
return config
|
828
1027
|
|
1028
|
+
coffeelint.invertLiterate = (source) ->
|
1029
|
+
source = CoffeeScript.helpers.invertLiterate source
|
1030
|
+
# Strip the first 4 spaces from every line. After this the markdown is
|
1031
|
+
# commented and all of the other code should be at their natural location.
|
1032
|
+
newSource = ""
|
1033
|
+
for line in source.split "\n"
|
1034
|
+
if line.match(/^#/)
|
1035
|
+
# strip trailing space
|
1036
|
+
line = line.replace /\s*$/, ''
|
1037
|
+
# Strip the first 4 spaces of every line. This is how Markdown
|
1038
|
+
# indicates code, so in the end this pulls everything back to where it
|
1039
|
+
# would be indented if it hadn't been written in literate style.
|
1040
|
+
line = line.replace /^\s{4}/g, ''
|
1041
|
+
newSource += "#{line}\n"
|
1042
|
+
|
1043
|
+
newSource
|
829
1044
|
|
830
1045
|
# Check the source against the given configuration and return an array
|
831
1046
|
# of any errors found. An error is an object with the following
|
@@ -839,14 +1054,16 @@ mergeDefaultConfig = (userConfig) ->
|
|
839
1054
|
# context: 'Optional details about why the rule was violated'
|
840
1055
|
# }
|
841
1056
|
#
|
842
|
-
coffeelint.lint = (source, userConfig = {}) ->
|
1057
|
+
coffeelint.lint = (source, userConfig = {}, literate = false) ->
|
1058
|
+
source = @invertLiterate source if literate
|
1059
|
+
|
843
1060
|
config = mergeDefaultConfig(userConfig)
|
844
1061
|
|
845
1062
|
# Check ahead for inline enabled rules
|
846
1063
|
disabled_initially = []
|
847
1064
|
for l in source.split('\n')
|
848
1065
|
s = regexes.configStatement.exec(l)
|
849
|
-
if s
|
1066
|
+
if s?.length > 2 and 'enable' in s
|
850
1067
|
for r in s[1..]
|
851
1068
|
unless r in ['enable','disable']
|
852
1069
|
unless r of config and config[r].level in ['warn','error']
|
data/lib/coffeelint.rb
CHANGED
@@ -9,51 +9,71 @@ module Coffeelint
|
|
9
9
|
@path ||= File.expand_path('../../coffeelint/src/coffeelint.coffee', __FILE__)
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.
|
12
|
+
def self.colorize(str, color_code)
|
13
|
+
"\e[#{color_code}m#{str}\e[0m"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.red(str, pretty_output = true)
|
17
|
+
pretty_output ? Coffeelint.colorize(str, 31) : str
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.green(str, pretty_output = true)
|
21
|
+
pretty_output ? Coffeelint.colorize(str, 32) : str
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.lint(script, config = {})
|
25
|
+
if !config[:config_file].nil?
|
26
|
+
fname = config.delete(:config_file)
|
27
|
+
config.merge!(JSON.parse(File.read(fname)))
|
28
|
+
end
|
13
29
|
coffeescriptSource = File.read(CoffeeScript::Source.path)
|
14
30
|
coffeelintSource = CoffeeScript.compile(File.read(Coffeelint.path))
|
15
31
|
context = ExecJS.compile(coffeescriptSource + coffeelintSource)
|
16
|
-
context.call('coffeelint.lint', script)
|
32
|
+
context.call('coffeelint.lint', script, config)
|
17
33
|
end
|
18
34
|
|
19
|
-
def self.lint_file(filename)
|
20
|
-
Coffeelint.lint(File.read(filename))
|
35
|
+
def self.lint_file(filename, config = {})
|
36
|
+
Coffeelint.lint(File.read(filename), config)
|
21
37
|
end
|
22
38
|
|
23
|
-
def self.lint_dir(directory)
|
39
|
+
def self.lint_dir(directory, config = {})
|
24
40
|
retval = {}
|
25
41
|
Dir.glob("#{directory}/**/*.coffee") do |name|
|
26
|
-
retval[name] = Coffeelint.lint_file(name)
|
42
|
+
retval[name] = Coffeelint.lint_file(name, config)
|
27
43
|
yield name, retval[name] if block_given?
|
28
44
|
end
|
29
45
|
retval
|
30
46
|
end
|
31
47
|
|
32
|
-
def self.display_test_results(name, errors)
|
33
|
-
good = "\u2713"
|
34
|
-
bad = "\u2717"
|
48
|
+
def self.display_test_results(name, errors, pretty_output = true)
|
49
|
+
good = pretty_output ? "\u2713" : 'Passed'
|
50
|
+
bad = pretty_output ? "\u2717" : 'Failed'
|
35
51
|
|
36
52
|
if errors.length == 0
|
37
|
-
puts " #{good}
|
53
|
+
puts " #{good} " + Coffeelint.green(name, pretty_output)
|
38
54
|
return true
|
39
55
|
else
|
40
|
-
puts " #{bad}
|
56
|
+
puts " #{bad} " + Coffeelint.red(name, pretty_output)
|
41
57
|
errors.each do |error|
|
42
|
-
|
58
|
+
print " #{bad} "
|
59
|
+
print Coffeelint.red(error["lineNumber"], pretty_output)
|
60
|
+
puts ": #{error["message"]}, #{error["context"]}."
|
43
61
|
end
|
44
62
|
return false
|
45
63
|
end
|
46
64
|
end
|
47
65
|
|
48
|
-
def self.run_test(file)
|
49
|
-
|
50
|
-
Coffeelint.
|
66
|
+
def self.run_test(file, config = {})
|
67
|
+
pretty_output = config.has_key?(:pretty_output) ? config.delete(:pretty_output) : true
|
68
|
+
result = Coffeelint.lint_file(file, config)
|
69
|
+
Coffeelint.display_test_results(file, result, pretty_output)
|
51
70
|
end
|
52
71
|
|
53
|
-
def self.run_test_suite(directory)
|
72
|
+
def self.run_test_suite(directory, config = {})
|
73
|
+
pretty_output = config.has_key?(:pretty_output) ? config.delete(:pretty_output) : true
|
54
74
|
success = true
|
55
|
-
Coffeelint.lint_dir(directory) do |name, errors|
|
56
|
-
result = Coffeelint.display_test_results(name, errors)
|
75
|
+
Coffeelint.lint_dir(directory, config) do |name, errors|
|
76
|
+
result = Coffeelint.display_test_results(name, errors, pretty_output)
|
57
77
|
success = false if not result
|
58
78
|
end
|
59
79
|
success
|
data/lib/coffeelint/version.rb
CHANGED
data/spec/coffeelint_spec.rb
CHANGED
@@ -7,4 +7,15 @@ describe Coffeelint do
|
|
7
7
|
result = results[0]
|
8
8
|
result['message'].should include 'trailing semicolon'
|
9
9
|
end
|
10
|
+
|
11
|
+
it 'should be able to disable a linter' do
|
12
|
+
results = Coffeelint.lint('apple;', :no_trailing_semicolons => { :level => "ignore" } )
|
13
|
+
results.length.should == 0
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should be able to take a config file in the parameters' do
|
17
|
+
File.open('/tmp/coffeelint.json', 'w') {|f| f.write(JSON.dump({:no_trailing_semicolons => { :level => "ignore" }})) }
|
18
|
+
results = Coffeelint.lint('apple;', :config_file => "/tmp/coffeelint.json")
|
19
|
+
results.length.should == 0
|
20
|
+
end
|
10
21
|
end
|
metadata
CHANGED
@@ -1,65 +1,53 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: coffeelint
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Zachary Bush
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
|
12
|
+
date: 2013-10-20 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
14
15
|
name: coffee-script
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ! '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
16
|
prerelease: false
|
22
|
-
|
23
|
-
requirements:
|
24
|
-
-
|
25
|
-
-
|
26
|
-
|
27
|
-
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- &id002
|
20
|
+
- ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
type: :runtime
|
24
|
+
version_requirements: *id001
|
25
|
+
- !ruby/object:Gem::Dependency
|
28
26
|
name: rspec
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ! '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
27
|
prerelease: false
|
36
|
-
|
37
|
-
requirements:
|
38
|
-
-
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ! '>='
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
28
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- *id002
|
48
31
|
type: :development
|
32
|
+
version_requirements: *id003
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rake
|
49
35
|
prerelease: false
|
50
|
-
|
51
|
-
requirements:
|
52
|
-
-
|
53
|
-
|
54
|
-
|
36
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- *id002
|
39
|
+
type: :development
|
40
|
+
version_requirements: *id004
|
55
41
|
description: Ruby bindings for coffeelint
|
56
|
-
email:
|
42
|
+
email:
|
57
43
|
- zach@zmbush.com
|
58
|
-
executables:
|
44
|
+
executables:
|
59
45
|
- coffeelint.rb
|
60
46
|
extensions: []
|
47
|
+
|
61
48
|
extra_rdoc_files: []
|
62
|
-
|
49
|
+
|
50
|
+
files:
|
63
51
|
- .gitignore
|
64
52
|
- .gitmodules
|
65
53
|
- Gemfile
|
@@ -76,29 +64,28 @@ files:
|
|
76
64
|
- spec/spec_helper.rb
|
77
65
|
- coffeelint/src/coffeelint.coffee
|
78
66
|
homepage: https://github.com/zipcodeman/coffeelint-ruby
|
79
|
-
licenses:
|
67
|
+
licenses:
|
80
68
|
- MIT
|
81
69
|
metadata: {}
|
70
|
+
|
82
71
|
post_install_message:
|
83
72
|
rdoc_options: []
|
84
|
-
|
73
|
+
|
74
|
+
require_paths:
|
85
75
|
- lib
|
86
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
-
requirements:
|
88
|
-
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
requirements:
|
93
|
-
- - ! '>='
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '0'
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- *id002
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- *id002
|
96
82
|
requirements: []
|
83
|
+
|
97
84
|
rubyforge_project:
|
98
|
-
rubygems_version: 2.
|
85
|
+
rubygems_version: 2.1.9
|
99
86
|
signing_key:
|
100
87
|
specification_version: 4
|
101
88
|
summary: Ruby bindings for coffeelint along with railtie to add rake task to rails
|
102
|
-
test_files:
|
89
|
+
test_files:
|
103
90
|
- spec/coffeelint_spec.rb
|
104
91
|
- spec/spec_helper.rb
|