Skip to content

Commit

Permalink
Add PropertyUnits linter
Browse files Browse the repository at this point in the history
  • Loading branch information
Ian McNally authored and sds committed Apr 4, 2015
1 parent 1db9499 commit 52b52db
Show file tree
Hide file tree
Showing 4 changed files with 261 additions and 0 deletions.
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ linters:
include_nested: false
max_properties: 10

PropertyUnits:
enabled: false
global: ['em', 'ex', '%', 'px', 'ch', 'cm', 'mm', 'in', 'pt', 'pc', 'rem', 'vh', 'vw', 'vmin', 'vmax']
properties: {}

PropertySortOrder:
enabled: true
ignore_unspecified: false
Expand Down
53 changes: 53 additions & 0 deletions lib/scss_lint/linter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Below is a list of linters supported by `scss-lint`, ordered alphabetically.
* [MergeableSelector](#mergeableselector)
* [NameFormat](#nameformat)
* [NestingDepth](#nestingdepth)
* [PropertyUnits](#propertyunits)
* [PlaceholderInExtend](#placeholderinextend)
* [PropertyCount](#propertycount)
* [PropertySortOrder](#propertysortorder)
Expand Down Expand Up @@ -902,6 +903,58 @@ Configuration Option | Description
---------------------|---------------------------------------------------------
`extra_properties` | List of extra properties to allow

## PropertyUnits

Configure what units are allowed globally, and/or on a per-property basis.

By default the linter will allow all property units by default, and developers can adjust the globally allowed units or set per-property exceptions as they see fit.

Defaults:
```yaml
global: ['em', 'ex', '%', 'px', 'ch', 'cm', 'mm', 'in', 'pt', 'pc', 'rem', 'vh', 'vw', 'vmin', 'vmax']
properties: {}
```

### Example setup

```yaml
PropertyUnits:
global: ['rem', 'em', '%'] # Allow relative units globally
properties:
margin: ['em', 'rem']
border: ['px']
line-height: [] # No units allowed
```

```scss
// Bad
p {
// not allowed globally
padding: 10px;
// not allowed on property
line-height: 55px;
border: 1rem solid blue;
margin: 10%;
}
// Good
p {
// allowed globally
padding: 1rem;
// allowed on property
line-height: 1;
border: 10px solid blue;
margin: 1em;
}
```

Configuration Option | Description
---------------------|---------------------------------------------------------
`global` | List of globally allowed units
`properties` | Property configurations. Each property has a list of allowed units.

## QualifyingElement

Avoid qualifying elements in selectors (also known as "tag-qualifying").
Expand Down
60 changes: 60 additions & 0 deletions lib/scss_lint/linter/property_units.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module SCSSLint
# Check for allowed units
class Linter::PropertyUnits < Linter
include LinterRegistry

def visit_prop(node)
@node = node
@global_allowed = config['global'].to_set
@properties = config['properties']
@property = node.name.join
@units = node.value.value.to_s.scan(/[a-zA-Z%]+/ix)

return if @units.empty?

global_allows_ok? && property_allows_ok?
end

private

def global_allows_ok?
not_allowed = units_not_allowed_globally
unless property_units_defined?
unless not_allowed.empty?
add_lint(@node, "Units are not allowed globally: #{not_allowed.join(' ')}")
end
return false
end
true
end

def property_allows_ok?
not_allowed = units_not_allowed_on_property
unless not_allowed.empty?
add_lint(@node, "Units are not allowed on #{@property}: #{not_allowed.join(' ')}")
return false
end
true
end

def units_not_allowed_globally
units_not_allowed @units, @global_allowed
end

def units_not_allowed_on_property
units_not_allowed @units, @properties[property_key]
end

def units_not_allowed(units, allowed)
units.select { |unit| !allowed.include?(unit) }
end

def property_units_defined?
@properties.key? property_key
end

def property_key
@property.gsub('-', '_')
end
end
end
143 changes: 143 additions & 0 deletions spec/scss_lint/linter/property_units_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
require 'spec_helper'

describe SCSSLint::Linter::PropertyUnits do
context 'when global units are set and local are not set' do
let(:linter_config) { { 'global' => ['rem'], 'properties' => {} } }

context 'when unit is allowed' do
let(:scss) { <<-SCSS }
p {
margin: 1rem;
}
SCSS

it { should_not report_lint }
end

context 'when unit is not allowed' do
let(:scss) { <<-SCSS }
p {
margin: 1px;
}
SCSS

it { should report_lint line: 2 }
end
end

context 'when global and local units are set' do
let(:linter_config) { { 'global' => ['rem'], 'properties' => { 'font_size' => ['px'] } } }

context 'when unit is allowed locally not globally' do
let(:scss) { <<-SCSS }
p {
font-size: 16px;
}
SCSS

it { should_not report_lint }
end

context 'when unit is allowed globally not locally' do
let(:scss) { <<-SCSS }
p {
margin: 1rem;
}
SCSS

it { should_not report_lint }
end

context 'when unit is not allowed globally nor locally' do
let(:scss) { <<-SCSS }
p {
margin: 1vh;
}
SCSS

it { should report_lint line: 2 }
end
end

context 'when local units are set and global are not set' do
let(:linter_config) { { 'global' => [], 'properties' => { 'margin' => ['rem'] } } }

context 'when unit is allowed locally not globally' do
let(:scss) { <<-SCSS }
p {
margin: 1rem;
}
SCSS

it { should_not report_lint }
end

context 'when unit is not allowed locally nor globally' do
let(:scss) { <<-SCSS }
p {
margin: 10px;
}
SCSS

it { should report_lint line: 2 }
end
end

context 'when multiple units are set on a property' do
let(:linter_config) { { 'global' => [], 'properties' => { 'margin' => %w[rem em] } } }

context 'when one of multiple units is used' do
let(:scss) { <<-SCSS }
p {
margin: 1rem;
}
SCSS

it { should_not report_lint }
end

context 'when another of multiple units is used' do
let(:scss) { <<-SCSS }
p {
margin: 1em;
}
SCSS

it { should_not report_lint }
end

context 'when a not allowed unit is used' do
let(:scss) { <<-SCSS }
p {
margin: 10px;
}
SCSS

it { should report_lint line: 2 }
end
end

context 'when no local units are allowed' do
let(:linter_config) { { 'global' => ['px'], 'properties' => { 'line_height' => [] } } }

context 'when a disallowed unit is used' do
let(:scss) { <<-SCSS }
p {
line-height: 10px;
}
SCSS

it { should report_lint line: 2 }
end

context 'when no unit is used' do
let(:scss) { <<-SCSS }
p {
line-height: 1;
}
SCSS

it { should_not report_lint }
end
end
end

0 comments on commit 52b52db

Please sign in to comment.