scss-lint 0.33.0 → 0.34.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.
- checksums.yaml +4 -4
- data/config/default.yml +19 -1
- data/data/properties.txt +4 -0
- data/lib/scss_lint.rb +1 -0
- data/lib/scss_lint/cli.rb +4 -42
- data/lib/scss_lint/config.rb +1 -45
- data/lib/scss_lint/control_comment_processor.rb +47 -15
- data/lib/scss_lint/file_finder.rb +57 -0
- data/lib/scss_lint/linter/bang_format.rb +1 -1
- data/lib/scss_lint/linter/border_zero.rb +25 -9
- data/lib/scss_lint/linter/color_keyword.rb +3 -13
- data/lib/scss_lint/linter/color_variable.rb +36 -0
- data/lib/scss_lint/linter/declaration_order.rb +2 -2
- data/lib/scss_lint/linter/important_rule.rb +12 -0
- data/lib/scss_lint/linter/indentation.rb +7 -1
- data/lib/scss_lint/linter/property_count.rb +44 -0
- data/lib/scss_lint/linter/property_sort_order.rb +73 -19
- data/lib/scss_lint/linter/string_quotes.rb +9 -0
- data/lib/scss_lint/linter/variable_for_property.rb +20 -0
- data/lib/scss_lint/linter/vendor_prefixes.rb +3 -3
- data/lib/scss_lint/runner.rb +5 -7
- data/lib/scss_lint/utils.rb +34 -0
- data/lib/scss_lint/version.rb +1 -1
- data/spec/scss_lint/cli_spec.rb +1 -1
- data/spec/scss_lint/config_spec.rb +4 -203
- data/spec/scss_lint/engine_spec.rb +4 -4
- data/spec/scss_lint/file_finder_spec.rb +110 -0
- data/spec/scss_lint/linter/bang_format_spec.rb +28 -18
- data/spec/scss_lint/linter/border_zero_spec.rb +50 -16
- data/spec/scss_lint/linter/color_keyword_spec.rb +16 -16
- data/spec/scss_lint/linter/color_variable_spec.rb +102 -0
- data/spec/scss_lint/linter/comment_spec.rb +9 -9
- data/spec/scss_lint/linter/compass/property_with_mixin_spec.rb +10 -10
- data/spec/scss_lint/linter/debug_statement_spec.rb +4 -4
- data/spec/scss_lint/linter/declaration_order_spec.rb +80 -80
- data/spec/scss_lint/linter/duplicate_property_spec.rb +30 -30
- data/spec/scss_lint/linter/else_placement_spec.rb +16 -16
- data/spec/scss_lint/linter/empty_line_between_blocks_spec.rb +38 -38
- data/spec/scss_lint/linter/empty_rule_spec.rb +4 -4
- data/spec/scss_lint/linter/final_newline_spec.rb +6 -6
- data/spec/scss_lint/linter/hex_length_spec.rb +16 -16
- data/spec/scss_lint/linter/hex_notation_spec.rb +16 -16
- data/spec/scss_lint/linter/hex_validation_spec.rb +6 -6
- data/spec/scss_lint/linter/id_selector_spec.rb +10 -10
- data/spec/scss_lint/linter/import_path_spec.rb +45 -45
- data/spec/scss_lint/linter/important_rule_spec.rb +43 -0
- data/spec/scss_lint/linter/indentation_spec.rb +103 -43
- data/spec/scss_lint/linter/leading_zero_spec.rb +45 -45
- data/spec/scss_lint/linter/mergeable_selector_spec.rb +32 -32
- data/spec/scss_lint/linter/name_format_spec.rb +75 -41
- data/spec/scss_lint/linter/nesting_depth_spec.rb +14 -14
- data/spec/scss_lint/linter/placeholder_in_extend_spec.rb +12 -12
- data/spec/scss_lint/linter/property_count_spec.rb +104 -0
- data/spec/scss_lint/linter/property_sort_order_spec.rb +138 -48
- data/spec/scss_lint/linter/property_spelling_spec.rb +14 -14
- data/spec/scss_lint/linter/qualifying_element_spec.rb +26 -26
- data/spec/scss_lint/linter/selector_depth_spec.rb +26 -26
- data/spec/scss_lint/linter/selector_format_spec.rb +114 -114
- data/spec/scss_lint/linter/shorthand_spec.rb +32 -32
- data/spec/scss_lint/linter/single_line_per_property_spec.rb +10 -10
- data/spec/scss_lint/linter/single_line_per_selector_spec.rb +24 -24
- data/spec/scss_lint/linter/space_after_comma_spec.rb +60 -60
- data/spec/scss_lint/linter/space_after_property_colon_spec.rb +44 -44
- data/spec/scss_lint/linter/space_after_property_name_spec.rb +6 -6
- data/spec/scss_lint/linter/space_before_brace_spec.rb +119 -119
- data/spec/scss_lint/linter/space_between_parens_spec.rb +48 -48
- data/spec/scss_lint/linter/string_quotes_spec.rb +74 -62
- data/spec/scss_lint/linter/trailing_semicolon_spec.rb +53 -54
- data/spec/scss_lint/linter/trailing_zero_spec.rb +34 -34
- data/spec/scss_lint/linter/unnecessary_mantissa_spec.rb +10 -10
- data/spec/scss_lint/linter/unnecessary_parent_reference_spec.rb +18 -18
- data/spec/scss_lint/linter/url_format_spec.rb +4 -4
- data/spec/scss_lint/linter/url_quotes_spec.rb +14 -14
- data/spec/scss_lint/linter/variable_for_property_spec.rb +115 -0
- data/spec/scss_lint/linter/vendor_prefixes_spec.rb +66 -56
- data/spec/scss_lint/linter/zero_unit_spec.rb +22 -22
- data/spec/scss_lint/linter_spec.rb +72 -28
- data/spec/scss_lint/runner_spec.rb +0 -1
- data/spec/scss_lint/selector_visitor_spec.rb +23 -23
- data/spec/spec_helper.rb +2 -2
- metadata +27 -12
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d9d896111a17640c23d31de062d34329fd52a56a
         | 
| 4 | 
            +
              data.tar.gz: 6f34a07866cd4b7c77a18137f2bec2570e9f31e5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d100dfddcde8591cbff342d88bc37f685ac337eb32b9193b87f09c46cf50dc61c04717a4e67fe843f6135fb186f8c5e43b7c6711680d67e766e56e71bb04ff94
         | 
| 7 | 
            +
              data.tar.gz: 65e67618d2e00e428a38adb5243236dea6464f17df75914937da60afbf3eded4f3b0e7be4d526b4d05c264c9a0ef5f5ed1cc13cbab3dac4a5cde3673f4e991d0
         | 
    
        data/config/default.yml
    CHANGED
    
    | @@ -10,10 +10,14 @@ linters: | |
| 10 10 |  | 
| 11 11 | 
             
              BorderZero:
         | 
| 12 12 | 
             
                enabled: true
         | 
| 13 | 
            +
                convention: zero # or `none`
         | 
| 13 14 |  | 
| 14 15 | 
             
              ColorKeyword:
         | 
| 15 16 | 
             
                enabled: true
         | 
| 16 17 |  | 
| 18 | 
            +
              ColorVariable:
         | 
| 19 | 
            +
                enabled: true
         | 
| 20 | 
            +
             | 
| 17 21 | 
             
              Comment:
         | 
| 18 22 | 
             
                enabled: true
         | 
| 19 23 |  | 
| @@ -55,6 +59,9 @@ linters: | |
| 55 59 | 
             
              IdSelector:
         | 
| 56 60 | 
             
                enabled: true
         | 
| 57 61 |  | 
| 62 | 
            +
              ImportantRule:
         | 
| 63 | 
            +
                enabled: true
         | 
| 64 | 
            +
             | 
| 58 65 | 
             
              ImportPath:
         | 
| 59 66 | 
             
                enabled: true
         | 
| 60 67 | 
             
                leading_underscore: false
         | 
| @@ -62,6 +69,7 @@ linters: | |
| 62 69 |  | 
| 63 70 | 
             
              Indentation:
         | 
| 64 71 | 
             
                enabled: true
         | 
| 72 | 
            +
                allow_non_nested_indentation: false
         | 
| 65 73 | 
             
                character: space # or 'tab'
         | 
| 66 74 | 
             
                width: 2
         | 
| 67 75 |  | 
| @@ -85,9 +93,15 @@ linters: | |
| 85 93 | 
             
              PlaceholderInExtend:
         | 
| 86 94 | 
             
                enabled: true
         | 
| 87 95 |  | 
| 96 | 
            +
              PropertyCount:
         | 
| 97 | 
            +
                enabled: false
         | 
| 98 | 
            +
                include_nested: false
         | 
| 99 | 
            +
                max_properties: 10
         | 
| 100 | 
            +
             | 
| 88 101 | 
             
              PropertySortOrder:
         | 
| 89 102 | 
             
                enabled: true
         | 
| 90 103 | 
             
                ignore_unspecified: false
         | 
| 104 | 
            +
                separate_groups: false
         | 
| 91 105 |  | 
| 92 106 | 
             
              PropertySpelling:
         | 
| 93 107 | 
             
                enabled: true
         | 
| @@ -129,7 +143,7 @@ linters: | |
| 129 143 |  | 
| 130 144 | 
             
              SpaceBeforeBrace:
         | 
| 131 145 | 
             
                enabled: true
         | 
| 132 | 
            -
                style: space
         | 
| 146 | 
            +
                style: space # or 'new_line'
         | 
| 133 147 | 
             
                allow_single_line_padding: false
         | 
| 134 148 |  | 
| 135 149 | 
             
              SpaceBetweenParens:
         | 
| @@ -158,6 +172,10 @@ linters: | |
| 158 172 | 
             
              UrlQuotes:
         | 
| 159 173 | 
             
                enabled: true
         | 
| 160 174 |  | 
| 175 | 
            +
              VariableForProperty:
         | 
| 176 | 
            +
                enabled: false
         | 
| 177 | 
            +
                properties: []
         | 
| 178 | 
            +
             | 
| 161 179 | 
             
              VendorPrefixes:
         | 
| 162 180 | 
             
                enabled: true
         | 
| 163 181 | 
             
                identifier_list: base
         | 
    
        data/data/properties.txt
    CHANGED
    
    | @@ -102,6 +102,9 @@ box-pack | |
| 102 102 | 
             
            box-reflect
         | 
| 103 103 | 
             
            box-shadow
         | 
| 104 104 | 
             
            box-sizing
         | 
| 105 | 
            +
            break-after
         | 
| 106 | 
            +
            break-before
         | 
| 107 | 
            +
            break-inside
         | 
| 105 108 | 
             
            buffered-rendering
         | 
| 106 109 | 
             
            caption-side
         | 
| 107 110 | 
             
            clear
         | 
| @@ -418,6 +421,7 @@ text-overline-style | |
| 418 421 | 
             
            text-overline-width
         | 
| 419 422 | 
             
            text-rendering
         | 
| 420 423 | 
             
            text-security
         | 
| 424 | 
            +
            text-size-adjust
         | 
| 421 425 | 
             
            text-shadow
         | 
| 422 426 | 
             
            text-stroke
         | 
| 423 427 | 
             
            text-stroke-color
         | 
    
        data/lib/scss_lint.rb
    CHANGED
    
    | @@ -5,6 +5,7 @@ require 'scss_lint/engine' | |
| 5 5 | 
             
            require 'scss_lint/location'
         | 
| 6 6 | 
             
            require 'scss_lint/lint'
         | 
| 7 7 | 
             
            require 'scss_lint/linter_registry'
         | 
| 8 | 
            +
            require 'scss_lint/file_finder'
         | 
| 8 9 | 
             
            require 'scss_lint/runner'
         | 
| 9 10 | 
             
            require 'scss_lint/selector_visitor'
         | 
| 10 11 | 
             
            require 'scss_lint/control_comment_processor'
         | 
    
        data/lib/scss_lint/cli.rb
    CHANGED
    
    | @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            require 'find'
         | 
| 2 1 | 
             
            require 'rainbow'
         | 
| 3 2 | 
             
            require 'rainbow/ext/string'
         | 
| 4 3 | 
             
            require 'scss_lint/options'
         | 
| @@ -49,7 +48,7 @@ module SCSSLint | |
| 49 48 |  | 
| 50 49 | 
             
                def scan_for_lints(options, config)
         | 
| 51 50 | 
             
                  runner = Runner.new(config)
         | 
| 52 | 
            -
                  runner.run( | 
| 51 | 
            +
                  runner.run(FileFinder.new(config).find(options[:files]))
         | 
| 53 52 | 
             
                  report_lints(options, runner.lints)
         | 
| 54 53 |  | 
| 55 54 | 
             
                  if runner.lints.any?(&:error?)
         | 
| @@ -87,9 +86,9 @@ module SCSSLint | |
| 87 86 | 
             
                def setup_configuration(options)
         | 
| 88 87 | 
             
                  config =
         | 
| 89 88 | 
             
                    if options[:config_file]
         | 
| 90 | 
            -
                      Config.load(options[:config_file]) | 
| 91 | 
            -
             | 
| 92 | 
            -
                       | 
| 89 | 
            +
                      Config.load(options[:config_file])
         | 
| 90 | 
            +
                    elsif File.exist?(Config::FILE_NAME)
         | 
| 91 | 
            +
                      Config.load(Config::FILE_NAME)
         | 
| 93 92 | 
             
                    else
         | 
| 94 93 | 
             
                      Config.default
         | 
| 95 94 | 
             
                    end
         | 
| @@ -123,43 +122,6 @@ module SCSSLint | |
| 123 122 | 
             
                  config
         | 
| 124 123 | 
             
                end
         | 
| 125 124 |  | 
| 126 | 
            -
                def files_to_lint(options, config)
         | 
| 127 | 
            -
                  if options[:files].empty?
         | 
| 128 | 
            -
                    options[:files] = config.scss_files
         | 
| 129 | 
            -
                  end
         | 
| 130 | 
            -
             | 
| 131 | 
            -
                  extract_files_from(options[:files]).reject do |file|
         | 
| 132 | 
            -
                    actual_config =
         | 
| 133 | 
            -
                      if !config.preferred && (config_for_file = Config.for_file(file))
         | 
| 134 | 
            -
                        merge_options_with_config(options, config_for_file.dup)
         | 
| 135 | 
            -
                      else
         | 
| 136 | 
            -
                        config
         | 
| 137 | 
            -
                      end
         | 
| 138 | 
            -
             | 
| 139 | 
            -
                    actual_config.excluded_file?(file)
         | 
| 140 | 
            -
                  end
         | 
| 141 | 
            -
                end
         | 
| 142 | 
            -
             | 
| 143 | 
            -
                # @param list [Array]
         | 
| 144 | 
            -
                def extract_files_from(list)
         | 
| 145 | 
            -
                  files = []
         | 
| 146 | 
            -
                  list.each do |file|
         | 
| 147 | 
            -
                    Find.find(file) do |f|
         | 
| 148 | 
            -
                      files << f if scssish_file?(f)
         | 
| 149 | 
            -
                    end
         | 
| 150 | 
            -
                  end
         | 
| 151 | 
            -
                  files.uniq
         | 
| 152 | 
            -
                end
         | 
| 153 | 
            -
             | 
| 154 | 
            -
                VALID_EXTENSIONS = %w[.css .scss]
         | 
| 155 | 
            -
                # @param file [String]
         | 
| 156 | 
            -
                # @return [Boolean]
         | 
| 157 | 
            -
                def scssish_file?(file)
         | 
| 158 | 
            -
                  return false unless FileTest.file?(file)
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                  VALID_EXTENSIONS.include?(File.extname(file))
         | 
| 161 | 
            -
                end
         | 
| 162 | 
            -
             | 
| 163 125 | 
             
                # @param options [Hash]
         | 
| 164 126 | 
             
                # @param lints [Array<Lint>]
         | 
| 165 127 | 
             
                def report_lints(options, lints)
         | 
    
        data/lib/scss_lint/config.rb
    CHANGED
    
    | @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            require 'pathname'
         | 
| 2 1 | 
             
            require 'yaml'
         | 
| 3 2 |  | 
| 4 3 | 
             
            module SCSSLint
         | 
| @@ -7,7 +6,6 @@ module SCSSLint | |
| 7 6 | 
             
                FILE_NAME = '.scss-lint.yml'
         | 
| 8 7 | 
             
                DEFAULT_FILE = File.join(SCSS_LINT_HOME, 'config', 'default.yml')
         | 
| 9 8 |  | 
| 10 | 
            -
                attr_accessor :preferred # If this config should be preferred over others
         | 
| 11 9 | 
             
                attr_reader :options, :warnings
         | 
| 12 10 |  | 
| 13 11 | 
             
                class << self
         | 
| @@ -27,17 +25,6 @@ module SCSSLint | |
| 27 25 | 
             
                    Config.new(config_options)
         | 
| 28 26 | 
             
                  end
         | 
| 29 27 |  | 
| 30 | 
            -
                  # Loads the configuration for a given file.
         | 
| 31 | 
            -
                  def for_file(file_path)
         | 
| 32 | 
            -
                    directory = File.dirname(File.expand_path(file_path))
         | 
| 33 | 
            -
                    @dir_to_config ||= {}
         | 
| 34 | 
            -
                    @dir_to_config[directory] ||=
         | 
| 35 | 
            -
                      begin
         | 
| 36 | 
            -
                        config_file = possible_config_files(directory).find(&:file?)
         | 
| 37 | 
            -
                        Config.load(config_file.to_s) if config_file
         | 
| 38 | 
            -
                      end
         | 
| 39 | 
            -
                  end
         | 
| 40 | 
            -
             | 
| 41 28 | 
             
                  def linter_name(linter)
         | 
| 42 29 | 
             
                    linter = linter.is_a?(Class) ? linter : linter.class
         | 
| 43 30 | 
             
                    linter.name.split('::')[2..-1].join('::')
         | 
| @@ -45,13 +32,6 @@ module SCSSLint | |
| 45 32 |  | 
| 46 33 | 
             
                private
         | 
| 47 34 |  | 
| 48 | 
            -
                  def possible_config_files(directory)
         | 
| 49 | 
            -
                    files = Pathname.new(directory)
         | 
| 50 | 
            -
                                    .enum_for(:ascend)
         | 
| 51 | 
            -
                                    .map { |path| path + FILE_NAME }
         | 
| 52 | 
            -
                    files << Pathname.new(FILE_NAME)
         | 
| 53 | 
            -
                  end
         | 
| 54 | 
            -
             | 
| 55 35 | 
             
                  def default_options_hash
         | 
| 56 36 | 
             
                    @default_options_hash ||= load_options_hash_from_file(DEFAULT_FILE)
         | 
| 57 37 | 
             
                  end
         | 
| @@ -74,7 +54,6 @@ module SCSSLint | |
| 74 54 | 
             
                    end
         | 
| 75 55 |  | 
| 76 56 | 
             
                    options = convert_single_options_to_arrays(options)
         | 
| 77 | 
            -
                    options = extend_inherited_configs(options, file)
         | 
| 78 57 | 
             
                    options = merge_wildcard_linter_options(options)
         | 
| 79 58 | 
             
                    options = ensure_exclude_paths_are_absolute(options, file)
         | 
| 80 59 | 
             
                    options = ensure_linter_exclude_paths_are_absolute(options, file)
         | 
| @@ -88,31 +67,13 @@ module SCSSLint | |
| 88 67 |  | 
| 89 68 | 
             
                    if options['exclude']
         | 
| 90 69 | 
             
                      # Ensure exclude is an array, since we allow user to specify a single
         | 
| 91 | 
            -
                      # string. | 
| 92 | 
            -
                      # inherit_from since this allows us to merge the excludes from that,
         | 
| 93 | 
            -
                      # rather than overwriting them.
         | 
| 70 | 
            +
                      # string.
         | 
| 94 71 | 
             
                      options['exclude'] = [options['exclude']].flatten
         | 
| 95 72 | 
             
                    end
         | 
| 96 73 |  | 
| 97 74 | 
             
                    options
         | 
| 98 75 | 
             
                  end
         | 
| 99 76 |  | 
| 100 | 
            -
                  # Loads and extends a list of inherited options with the given options.
         | 
| 101 | 
            -
                  def extend_inherited_configs(options, original_file)
         | 
| 102 | 
            -
                    return options unless options['inherit_from']
         | 
| 103 | 
            -
                    options = options.dup
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                    includes = [options.delete('inherit_from')].flatten.map do |include_file|
         | 
| 106 | 
            -
                      load_options_hash_from_file(path_relative_to_config(include_file, original_file))
         | 
| 107 | 
            -
                    end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                    merged_includes = includes[1..-1].inject(includes.first) do |merged, include_file|
         | 
| 110 | 
            -
                      smart_merge(merged, include_file)
         | 
| 111 | 
            -
                    end
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                    smart_merge(merged_includes, options)
         | 
| 114 | 
            -
                  end
         | 
| 115 | 
            -
             | 
| 116 77 | 
             
                  # Merge options from wildcard linters into individual linter configs
         | 
| 117 78 | 
             
                  def merge_wildcard_linter_options(options)
         | 
| 118 79 | 
             
                    options = options.dup
         | 
| @@ -211,11 +172,6 @@ module SCSSLint | |
| 211 172 | 
             
                  validate_linters
         | 
| 212 173 | 
             
                end
         | 
| 213 174 |  | 
| 214 | 
            -
                def ==(other)
         | 
| 215 | 
            -
                  super || @options == other.options
         | 
| 216 | 
            -
                end
         | 
| 217 | 
            -
                alias_method :eql?, :==
         | 
| 218 | 
            -
             | 
| 219 175 | 
             
                def enabled_linters
         | 
| 220 176 | 
             
                  LinterRegistry.extract_linters_from(@options['linters'].keys).select do |linter|
         | 
| 221 177 | 
             
                    linter_options(linter)['enabled']
         | 
| @@ -20,25 +20,18 @@ module SCSSLint | |
| 20 20 | 
             
                #
         | 
| 21 21 | 
             
                # @param node [Sass::Tree::Node]
         | 
| 22 22 | 
             
                def before_node_visit(node)
         | 
| 23 | 
            -
                  return unless node | 
| 23 | 
            +
                  return unless command = extract_command(node)
         | 
| 24 24 |  | 
| 25 | 
            -
                   | 
| 26 | 
            -
                    \*\s* # Comment line start marker
         | 
| 27 | 
            -
                    scss-lint:
         | 
| 28 | 
            -
                    (?<command>disable|enable)\s+
         | 
| 29 | 
            -
                    (?<linters>.*?)
         | 
| 30 | 
            -
                    \s*(?:\*\/|\n) # Comment end marker or end of line
         | 
| 31 | 
            -
                  /.match(node.value.first)
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                  linters = match[:linters].split(/\s*,\s*|\s+/)
         | 
| 25 | 
            +
                  linters = command[:linters]
         | 
| 34 26 | 
             
                  return unless linters.include?('all') || linters.include?(@linter.name)
         | 
| 35 27 |  | 
| 36 | 
            -
                  process_command( | 
| 28 | 
            +
                  process_command(command[:action], node)
         | 
| 37 29 |  | 
| 38 30 | 
             
                  # Is the control comment the only thing on this line?
         | 
| 39 | 
            -
                  return if  | 
| 31 | 
            +
                  return if node.is_a?(Sass::Tree::RuleNode) ||
         | 
| 32 | 
            +
                            %r{^\s*(//|/\*)}.match(@linter.engine.lines[node.line - 1])
         | 
| 40 33 |  | 
| 41 | 
            -
                  #  | 
| 34 | 
            +
                  # Otherwise, pop since we only want comment to apply to the single line
         | 
| 42 35 | 
             
                  pop_control_comment_stack(node)
         | 
| 43 36 | 
             
                end
         | 
| 44 37 |  | 
| @@ -53,6 +46,29 @@ module SCSSLint | |
| 53 46 |  | 
| 54 47 | 
             
              private
         | 
| 55 48 |  | 
| 49 | 
            +
                def extract_command(node)
         | 
| 50 | 
            +
                  comment =
         | 
| 51 | 
            +
                    case node
         | 
| 52 | 
            +
                    when Sass::Tree::CommentNode
         | 
| 53 | 
            +
                      node.value.first
         | 
| 54 | 
            +
                    when Sass::Tree::RuleNode
         | 
| 55 | 
            +
                      node.rule.select { |chunk| chunk.is_a?(String) }.join
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  return unless match = %r{
         | 
| 59 | 
            +
                    (/|\*)\s* # Comment start marker
         | 
| 60 | 
            +
                    scss-lint:
         | 
| 61 | 
            +
                    (?<action>disable|enable)\s+
         | 
| 62 | 
            +
                    (?<linters>.*?)
         | 
| 63 | 
            +
                    \s*(?:\*/|\n) # Comment end marker or end of line
         | 
| 64 | 
            +
                  }x.match(comment)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  {
         | 
| 67 | 
            +
                    action: match[:action],
         | 
| 68 | 
            +
                    linters: match[:linters].split(/\s*,\s*|\s+/),
         | 
| 69 | 
            +
                  }
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 56 72 | 
             
                def process_command(command, node)
         | 
| 57 73 | 
             
                  case command
         | 
| 58 74 | 
             
                  when 'disable'
         | 
| @@ -71,13 +87,29 @@ module SCSSLint | |
| 71 87 | 
             
                  # apply (if it is a control comment enable node, it will be the line of
         | 
| 72 88 | 
             
                  # the comment itself).
         | 
| 73 89 | 
             
                  child = node
         | 
| 74 | 
            -
                   | 
| 75 | 
            -
             | 
| 90 | 
            +
                  prev_child = node
         | 
| 91 | 
            +
                  while (child = last_child(child)) != prev_child
         | 
| 92 | 
            +
                    prev_child = child
         | 
| 76 93 | 
             
                  end
         | 
| 77 94 |  | 
| 78 95 | 
             
                  end_line = child.line
         | 
| 79 96 |  | 
| 80 97 | 
             
                  @disabled_lines.merge(start_line..end_line)
         | 
| 81 98 | 
             
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                # Gets the child of the node that resides on the lowest line in the file.
         | 
| 101 | 
            +
                #
         | 
| 102 | 
            +
                # This is necessary due to the fact that our monkey patching of the parse
         | 
| 103 | 
            +
                # tree's {#children} method does not return nodes sorted by their line
         | 
| 104 | 
            +
                # number.
         | 
| 105 | 
            +
                #
         | 
| 106 | 
            +
                # @param node [Sass::Tree::Node, Sass::Script::Tree::Node]
         | 
| 107 | 
            +
                # @return [Sass::Tree::Node, Sass::Script::Tree::Node]
         | 
| 108 | 
            +
                def last_child(node)
         | 
| 109 | 
            +
                  node.children.inject(node) do |lowest, child|
         | 
| 110 | 
            +
                    return lowest unless child.respond_to?(:line)
         | 
| 111 | 
            +
                    lowest.line < child.line ? child : lowest
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
                end
         | 
| 82 114 | 
             
              end
         | 
| 83 115 | 
             
            end
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require 'find'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module SCSSLint
         | 
| 4 | 
            +
              # Finds all SCSS files that should be linted given a set of paths, globs, and
         | 
| 5 | 
            +
              # configuration.
         | 
| 6 | 
            +
              class FileFinder
         | 
| 7 | 
            +
                # List of extensions of files to include when only a directory is specified
         | 
| 8 | 
            +
                # as a path.
         | 
| 9 | 
            +
                VALID_EXTENSIONS = %w[.css .scss]
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                # Create a {FileFinder}.
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                # @param config [SCSSLint::Config]
         | 
| 14 | 
            +
                def initialize(config)
         | 
| 15 | 
            +
                  @config = config
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                # Find all files that match given the specified options.
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                # @param patterns [Array<String>] a list of file paths and glob patterns
         | 
| 21 | 
            +
                def find(patterns)
         | 
| 22 | 
            +
                  # If no explicit patterns given, use patterns listed in config
         | 
| 23 | 
            +
                  patterns = @config.scss_files if patterns.empty?
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  extract_files_from(patterns).reject do |file|
         | 
| 26 | 
            +
                    @config.excluded_file?(file)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              private
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                # @param list [Array]
         | 
| 33 | 
            +
                def extract_files_from(list)
         | 
| 34 | 
            +
                  files = []
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  list.each do |file|
         | 
| 37 | 
            +
                    if File.directory?(file)
         | 
| 38 | 
            +
                      Find.find(file) do |f|
         | 
| 39 | 
            +
                        files << f if scssish_file?(f)
         | 
| 40 | 
            +
                      end
         | 
| 41 | 
            +
                    else
         | 
| 42 | 
            +
                      files << file # Otherwise include file as-is
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  files.uniq
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                # @param file [String]
         | 
| 50 | 
            +
                # @return [true,false]
         | 
| 51 | 
            +
                def scssish_file?(file)
         | 
| 52 | 
            +
                  return false unless FileTest.file?(file)
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  VALID_EXTENSIONS.include?(File.extname(file))
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -6,7 +6,7 @@ module SCSSLint | |
| 6 6 | 
             
                STOPPING_CHARACTERS = ['!', "'", '"', nil]
         | 
| 7 7 |  | 
| 8 8 | 
             
                def visit_prop(node)
         | 
| 9 | 
            -
                  return unless node. | 
| 9 | 
            +
                  return unless source_from_range(node.source_range).include?('!')
         | 
| 10 10 | 
             
                  return unless check_spacing(node)
         | 
| 11 11 |  | 
| 12 12 | 
             
                  before_qualifier = config['space_before_bang'] ? '' : 'not '
         | 
| @@ -1,16 +1,12 @@ | |
| 1 1 | 
             
            module SCSSLint
         | 
| 2 | 
            -
              #  | 
| 2 | 
            +
              # Enforce a particular value for empty borders.
         | 
| 3 3 | 
             
              class Linter::BorderZero < Linter
         | 
| 4 4 | 
             
                include LinterRegistry
         | 
| 5 5 |  | 
| 6 | 
            -
                 | 
| 7 | 
            -
                   | 
| 8 | 
            -
                   | 
| 9 | 
            -
             | 
| 10 | 
            -
                  add_lint(node, '`border: 0;` is preferred over `border: none;`')
         | 
| 11 | 
            -
                end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
              private
         | 
| 6 | 
            +
                CONVENTION_TO_PREFERENCE = {
         | 
| 7 | 
            +
                  'zero' => %w[0 none],
         | 
| 8 | 
            +
                  'none' => %w[none 0],
         | 
| 9 | 
            +
                }
         | 
| 14 10 |  | 
| 15 11 | 
             
                BORDER_PROPERTIES = %w[
         | 
| 16 12 | 
             
                  border
         | 
| @@ -19,5 +15,25 @@ module SCSSLint | |
| 19 15 | 
             
                  border-bottom
         | 
| 20 16 | 
             
                  border-left
         | 
| 21 17 | 
             
                ]
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def visit_root(_node)
         | 
| 20 | 
            +
                  @preference = CONVENTION_TO_PREFERENCE[config['convention']]
         | 
| 21 | 
            +
                  yield # Continue linting children
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def visit_prop(node)
         | 
| 25 | 
            +
                  return unless BORDER_PROPERTIES.include?(node.name.first.to_s)
         | 
| 26 | 
            +
                  check_border(node, node.value.to_sass.strip)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              private
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def check_border(node, border)
         | 
| 32 | 
            +
                  return unless %w[0 none].include?(border)
         | 
| 33 | 
            +
                  return if @preference[0] == border
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  add_lint(node, "`border: #{@preference[0]} is preferred over " \
         | 
| 36 | 
            +
                                 "`border: #{@preference[1]}`")
         | 
| 37 | 
            +
                end
         | 
| 22 38 | 
             
              end
         | 
| 23 39 | 
             
            end
         |