scss-lint 0.5.2 → 0.6

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.
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