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 CHANGED
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'scss_lint/cli'
3
+ require 'scss_lint'
4
4
 
5
- SCSSLint::CLI.new ARGV
5
+ SCSSLint::CLI.new(ARGV).tap do |cli|
6
+ cli.parse_arguments
7
+ cli.run
8
+ end
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
- def initialize(args)
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
- files = SCSSLint.extract_files_from(opts)
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
- runner.run files
17
- report_lints(runner.lints)
18
- exit 1 if runner.lints?
19
- rescue NoFilesError => ex
20
- puts ex.message
21
- exit -1
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 report_lints(lints)
26
- lints.sort_by { |l| [l.filename, l.line] }.each do |lint|
27
- if lint.filename
28
- print "#{lint.filename}:".yellow
29
- else
30
- print 'line'.yellow
31
- end
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
- puts "#{lint.line} - #{lint.description}"
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
- if prop_node.value.is_a?(Sass::Script::String) &&
26
- prop_node.value.to_s.strip =~ /\A(\S+\s+\S+(\s+\S+){0,2})\Z/
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,13 @@
1
+ module SCSSLint
2
+ class Reporter
3
+ attr_reader :lints
4
+
5
+ def initialize(lints)
6
+ @lints = lints
7
+ end
8
+
9
+ def report_lints
10
+ raise NotImplementedError, 'You must implement report_lints'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'colorize'
2
+
3
+ module SCSSLint
4
+ class Reporter::DefaultReporter < Reporter
5
+ def report_lints
6
+ lints.map do |lint|
7
+ "#{lint.filename}:".yellow + "#{lint.line} - #{lint.description}"
8
+ end.join("\n")
9
+ end
10
+ end
11
+ 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
@@ -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 run(files = [])
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 LinterRegistry.linters.empty?
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
- LinterRegistry.linters.each do |linter|
34
+ linters.each do |linter|
26
35
  @lints += linter.run(engine)
27
36
  end
28
37
  rescue Sass::SyntaxError => ex
@@ -1,3 +1,3 @@
1
1
  module SCSSLint
2
- VERSION = '0.5.2'
2
+ VERSION = '0.6'
3
3
  end
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.5.2
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-01-25 00:00:00.000000000 Z
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