scss-lint 0.5.2 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/scss-lint +5 -2
- data/lib/scss_lint.rb +17 -1
- data/lib/scss_lint/cli.rb +79 -21
- data/lib/scss_lint/linter/property_format_linter.rb +2 -1
- data/lib/scss_lint/linter/shorthand_linter.rb +11 -2
- data/lib/scss_lint/linter_registry.rb +13 -0
- data/lib/scss_lint/reporter.rb +13 -0
- data/lib/scss_lint/reporter/default_reporter.rb +11 -0
- data/lib/scss_lint/reporter/xml_reporter.rb +21 -0
- data/lib/scss_lint/runner.rb +13 -4
- data/lib/scss_lint/version.rb +1 -1
- metadata +21 -2
data/bin/scss-lint
CHANGED
data/lib/scss_lint.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'find'
|
2
2
|
|
3
3
|
module SCSSLint
|
4
|
+
autoload :CLI, 'scss_lint/cli'
|
4
5
|
autoload :Engine, 'scss_lint/engine'
|
5
6
|
autoload :Lint, 'scss_lint/lint'
|
6
7
|
autoload :LinterRegistry, 'scss_lint/linter_registry'
|
7
8
|
autoload :Linter, 'scss_lint/linter'
|
9
|
+
autoload :Reporter, 'scss_lint/reporter'
|
8
10
|
autoload :Runner, 'scss_lint/runner'
|
9
11
|
|
10
12
|
# Load all linters
|
@@ -12,15 +14,29 @@ module SCSSLint
|
|
12
14
|
require file
|
13
15
|
end
|
14
16
|
|
17
|
+
# Load all reporters
|
18
|
+
Dir[File.expand_path('scss_lint/reporter/*.rb', File.dirname(__FILE__))].each do |file|
|
19
|
+
require file
|
20
|
+
end
|
21
|
+
|
15
22
|
class << self
|
16
23
|
def extract_files_from(list)
|
17
24
|
files = []
|
18
25
|
list.each do |file|
|
19
26
|
Find.find(file) do |f|
|
20
|
-
files << f
|
27
|
+
files << f if scssish_file?(f)
|
21
28
|
end
|
22
29
|
end
|
23
30
|
files.uniq
|
24
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
VALID_EXTENSIONS = %w[.css .scss]
|
36
|
+
def scssish_file?(file)
|
37
|
+
return false unless FileTest.file?(file)
|
38
|
+
|
39
|
+
VALID_EXTENSIONS.include?(File.extname(file))
|
40
|
+
end
|
25
41
|
end
|
26
42
|
end
|
data/lib/scss_lint/cli.rb
CHANGED
@@ -1,37 +1,95 @@
|
|
1
1
|
require 'scss_lint'
|
2
|
-
require 'colorize'
|
3
2
|
require 'optparse'
|
4
3
|
|
5
4
|
module SCSSLint
|
6
5
|
class CLI
|
7
|
-
|
8
|
-
opts = OptionParser.new do |opts|
|
9
|
-
opts.banner = 'Usage: scss-lint [scss-files]'
|
10
|
-
end.parse!(args)
|
6
|
+
attr_accessor :options
|
11
7
|
|
12
|
-
|
8
|
+
def initialize(args = [])
|
9
|
+
@args = args
|
10
|
+
@options = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_arguments
|
14
|
+
parser = OptionParser.new do |opts|
|
15
|
+
opts.banner = "Usage: #{opts.program_name} [options] [scss-files]"
|
16
|
+
|
17
|
+
opts.separator ''
|
18
|
+
opts.separator 'Common options:'
|
19
|
+
|
20
|
+
opts.on('-e', '--exclude file,...', Array,
|
21
|
+
'List of file names to exclude') do |files|
|
22
|
+
options[:excluded_files] = files
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('-i', '--ignore-linter linter,...', Array,
|
26
|
+
"Specify which linters you don't want to run") do |linters|
|
27
|
+
options[:ignored_linters] = linters
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
31
|
+
print_help opts.help
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
35
|
+
print_version opts.program_name, VERSION
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on('-x', '--xml', 'Output the results in XML format') do
|
39
|
+
options[:reporter] = SCSSLint::Reporter::XMLReporter
|
40
|
+
end
|
41
|
+
end
|
13
42
|
|
14
|
-
runner = Runner.new
|
15
43
|
begin
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
44
|
+
parser.parse!(@args)
|
45
|
+
|
46
|
+
# Take the rest of the arguments as files/directories
|
47
|
+
options[:files] = @args
|
48
|
+
rescue OptionParser::InvalidOption => ex
|
49
|
+
print_help parser.help, ex
|
22
50
|
end
|
23
51
|
end
|
24
52
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
53
|
+
def run
|
54
|
+
runner = Runner.new(options)
|
55
|
+
runner.run(find_files)
|
56
|
+
report_lints(runner.lints)
|
57
|
+
halt 1 if runner.lints?
|
58
|
+
rescue NoFilesError, NoSuchLinter => ex
|
59
|
+
puts ex.message
|
60
|
+
halt -1
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
32
64
|
|
33
|
-
|
65
|
+
def find_files
|
66
|
+
excluded_files = options.fetch(:excluded_files, [])
|
67
|
+
|
68
|
+
SCSSLint.extract_files_from(options[:files]).reject do |file|
|
69
|
+
excluded_files.include?(file)
|
34
70
|
end
|
35
71
|
end
|
72
|
+
|
73
|
+
def report_lints(lints)
|
74
|
+
sorted_lints = lints.sort_by { |l| [l.filename, l.line] }
|
75
|
+
reporter = options.fetch(:reporter, Reporter::DefaultReporter).new(sorted_lints)
|
76
|
+
puts reporter.report_lints
|
77
|
+
end
|
78
|
+
|
79
|
+
def print_help(help_message, err = nil)
|
80
|
+
puts err, '' if err
|
81
|
+
puts help_message
|
82
|
+
halt
|
83
|
+
end
|
84
|
+
|
85
|
+
def print_version(program_name, version)
|
86
|
+
puts "#{program_name} #{version}"
|
87
|
+
halt
|
88
|
+
end
|
89
|
+
|
90
|
+
# Used for ease-of testing
|
91
|
+
def halt(exit_status = 0)
|
92
|
+
exit exit_status
|
93
|
+
end
|
36
94
|
end
|
37
95
|
end
|
@@ -17,7 +17,8 @@ module SCSSLint
|
|
17
17
|
|
18
18
|
def description
|
19
19
|
'Property declarations should always be on one line of the form ' <<
|
20
|
-
'`name: value;` or `name: [value] {`'
|
20
|
+
'`name: value;` or `name: [value] {` ' <<
|
21
|
+
'(are you missing a trailing semi-colon?)'
|
21
22
|
end
|
22
23
|
|
23
24
|
private
|
@@ -20,10 +20,19 @@ module SCSSLint
|
|
20
20
|
end
|
21
21
|
|
22
22
|
private
|
23
|
+
SHORTHANDABLE_PROPERTIES = %w[border-color
|
24
|
+
border-radius
|
25
|
+
border-style
|
26
|
+
border-width
|
27
|
+
margin
|
28
|
+
padding]
|
23
29
|
|
24
30
|
def check_valid_shorthand_value(prop_node)
|
25
|
-
|
26
|
-
|
31
|
+
unless SHORTHANDABLE_PROPERTIES.include? prop_node.name.first.to_s
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
if prop_node.value.to_s.strip =~ /\A(\S+\s+\S+(\s+\S+){0,2})\Z/
|
27
36
|
return create_lint(prop_node) unless valid_shorthand?($1)
|
28
37
|
end
|
29
38
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
module SCSSLint
|
2
|
+
class NoSuchLinter < StandardError; end
|
3
|
+
|
2
4
|
module LinterRegistry
|
3
5
|
@linters = []
|
4
6
|
|
@@ -8,6 +10,17 @@ module SCSSLint
|
|
8
10
|
def included(base)
|
9
11
|
@linters << base
|
10
12
|
end
|
13
|
+
|
14
|
+
def extract_linters_from(linter_names)
|
15
|
+
linter_names.map do |linter_name|
|
16
|
+
begin
|
17
|
+
linter_class = linter_name.split('_').map(&:capitalize).join('')
|
18
|
+
Kernel.const_get(linter_class)
|
19
|
+
rescue NameError
|
20
|
+
raise NoSuchLinter.new("Linter #{linter_class} does not exist")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
11
24
|
end
|
12
25
|
end
|
13
26
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SCSSLint
|
2
|
+
class Reporter::XMLReporter < Reporter
|
3
|
+
def report_lints
|
4
|
+
output = '<?xml version="1.0" encoding="utf-8"?>'
|
5
|
+
|
6
|
+
output << '<lint>'
|
7
|
+
lints.group_by(&:filename).each do |filename, file_lints|
|
8
|
+
output << "<file name='#{filename}'>"
|
9
|
+
|
10
|
+
file_lints.each do |lint|
|
11
|
+
output << "<issue line='#{lint.line}' severity='warning' reason='#{lint.description}' />"
|
12
|
+
end
|
13
|
+
|
14
|
+
output << '</file>'
|
15
|
+
end
|
16
|
+
output << '</lint>'
|
17
|
+
|
18
|
+
output
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/scss_lint/runner.rb
CHANGED
@@ -6,13 +6,22 @@ module SCSSLint
|
|
6
6
|
class NoLintersError < StandardError; end
|
7
7
|
|
8
8
|
class Runner
|
9
|
-
attr_reader :lints
|
9
|
+
attr_reader :linters, :lints
|
10
10
|
|
11
|
-
def
|
11
|
+
def initialize(options = {})
|
12
12
|
@lints = []
|
13
13
|
|
14
|
+
ignored_linters = LinterRegistry.
|
15
|
+
extract_linters_from(options.fetch(:ignored_linters, []))
|
16
|
+
|
17
|
+
@linters = LinterRegistry.linters.reject do |linter|
|
18
|
+
ignored_linters.include?(linter)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(files = [])
|
14
23
|
raise NoFilesError.new('No SCSS files specified') if files.empty?
|
15
|
-
raise NoLintersError.new('No linters specified') if
|
24
|
+
raise NoLintersError.new('No linters specified') if linters.empty?
|
16
25
|
|
17
26
|
files.each do |file|
|
18
27
|
find_lints(file)
|
@@ -22,7 +31,7 @@ module SCSSLint
|
|
22
31
|
def find_lints(file)
|
23
32
|
engine = Engine.new(file)
|
24
33
|
|
25
|
-
|
34
|
+
linters.each do |linter|
|
26
35
|
@lints += linter.run(engine)
|
27
36
|
end
|
28
37
|
rescue Sass::SyntaxError => ex
|
data/lib/scss_lint/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scss-lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.6'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-03-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: colorize
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: rspec
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,6 +100,9 @@ files:
|
|
84
100
|
- lib/scss_lint/linter/type_in_id_selector_linter.rb
|
85
101
|
- lib/scss_lint/linter/zero_unit_linter.rb
|
86
102
|
- lib/scss_lint/linter_registry.rb
|
103
|
+
- lib/scss_lint/reporter.rb
|
104
|
+
- lib/scss_lint/reporter/default_reporter.rb
|
105
|
+
- lib/scss_lint/reporter/xml_reporter.rb
|
87
106
|
- lib/scss_lint/runner.rb
|
88
107
|
- lib/scss_lint/version.rb
|
89
108
|
- bin/scss-lint
|