grouped_property_scss_linter 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e22237fdcbef363b71f89896640289081051eeff
4
+ data.tar.gz: 0056fd882b1a9b93488294289b4dfa5b2c21d90e
5
+ SHA512:
6
+ metadata.gz: cfece3ebdca1ca05691671646bb7530c1fc2733674911c1f63aae367688fcceba950fa14a626c780575874a35ae66f625e54971111f87e32c1e8c7c4a3d6f1fa
7
+ data.tar.gz: bbf00eaf2b8a150e0da8c9db5d3661274f54c94eef766e3cef375f637d792ea72a8e9cc3f97893fd4417063c721e5fc5ea521339d8f3735cb17bb86efe7b72a3
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.scss-lint.yml ADDED
@@ -0,0 +1,17 @@
1
+ linters:
2
+ GroupedPropertyOrder:
3
+ enabled: true
4
+
5
+ # defaults: applied to all groups
6
+ defaults:
7
+ space_around: true
8
+ max_no_space: 3
9
+
10
+ # preferred style
11
+ style: grouped-smacss
12
+
13
+ # or a definition of your own. Note that this takes precedence over style
14
+ groups:
15
+
16
+ # whether you get extended hinting information in the output
17
+ extended_hinting: false
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in grouped_property_scss_linter.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016–2017 Jon Pearse
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,181 @@
1
+ h1. Grouped Property Linter for SCSS-Lint
2
+
3
+ This is a plugin linter for "SCSS-Lint":https://github.com/brigade/scss-lint that provides a saner alternative to the built-in @PropertySortOrder@ linter.
4
+
5
+ Instead of requiring properties to be arranged in a strict order, it instead allows groups of properties (eg: @top@, @right@, @bottom@ & @left@) to be defined, and then lints the order of the _groups_ in your SASS.
6
+ As long as properties are grouped correctly, the order of individual properties is unimportant.
7
+
8
+ h2. Examples
9
+
10
+ Using the default configuration:
11
+
12
+ *Bad*
13
+
14
+ <pre><code lang="css">.selector {
15
+ padding: .625rem;
16
+
17
+ text-decoration: underline;
18
+ font-size: 1rem;
19
+ line-height: 1.3;
20
+ font-weight: bold;
21
+ color: rgba(20, 20, 20, .8);
22
+
23
+ display: inline-block;
24
+ background: #F00;
25
+ }</code></pre>
26
+
27
+ *Good*
28
+
29
+ <pre><code lang="css">.selector {
30
+ display: inline-block;
31
+ padding: .625rem;
32
+
33
+ color: rgba(20, 20, 20, .8);
34
+ background: #F00;
35
+
36
+ font-size: 1rem;
37
+ line-height: 1.3em;
38
+ font-weight: bold;
39
+ text-decoration: underline;
40
+ }</code></pre>
41
+
42
+ Because the order of individual properties within a group is ignored, neither of the selectors below would generate a warning.
43
+
44
+ <pre><code lang="css">.selector-one {
45
+ display: block;
46
+
47
+ height: 10em;
48
+ width: 90%;
49
+ }
50
+
51
+ .selector-two {
52
+ display: block;
53
+
54
+ width: 90%;
55
+ height: 10em;
56
+ }</code></pre>
57
+
58
+ h2. Usage
59
+
60
+ In order to use this linter, you’ll need to modify both your Gemfile and scss-lint configuration file (typically @.scss-lint@).
61
+
62
+ *Gemfile*
63
+
64
+ <pre><code lang="ruby">gem 'grouped_property_scss_linter'</code></pre>
65
+
66
+ *SCSS-Lint configuration file*
67
+
68
+ You will need to add @grouped_property_scss_linter@ to the @plugin_gems@ variable:
69
+
70
+ <pre><code lang="yaml">plugin_gems: ['grouped_property_scss_linter']</code></pre>
71
+
72
+ h2. Configuration
73
+
74
+ When included, this linter is enabled by default, and enforces a modified version of "SMACSS’s categories":https://smacss.com/book/categorizing
75
+
76
+ The configuration may be altered in the same way as other linters, by adding a section to your SCSS-Lint configuration file.
77
+
78
+ <pre><code lang="yaml">linters:
79
+ GroupedPropertyOrder:
80
+ enabled: true
81
+ defaults:
82
+ space_around: true
83
+ max_no_space: 3
84
+ style: smacss
85
+ groups:
86
+ </code></pre>
87
+
88
+ h3. Options
89
+
90
+ - @enabled@ _(boolean)_ := switches the module on and off (default: on)
91
+ - @defaults@ _(hash)_ := default linting settings that are applied to all groups (can be overridden per-group)
92
+ - @style@ _(string, optional)_ := the name of a preconfigured style (see below, defaults to @grouped-smacss@)
93
+ - @groups@ _(hash, optional)_ := a hash of configured groups. Note that specifying anything here will override the @style@ option
94
+ - @extended_hinting@ _(boolean, optional)_ := enables additional group information in hinting output (default @false@)
95
+
96
+ h4. Default options
97
+
98
+ - @space_around@ _(boolean)_ := whether to require space around individual groups (default: true)
99
+ - @max_no_space@ _(int)_ := the maximum number of properties that can be specified in a group before space is required around it (default: 3, ignored if @space_around@ is @false@)
100
+
101
+ h4. Predefined styles
102
+
103
+ There a number of property orders/styles supplied with the gem. These are:
104
+
105
+ - @smacss@ := an implementation of "SMACSS":https://smacss.com/book/formatting
106
+ - @grouped-smacss@ _(default)_ := a tweaked version of SMACSS with slightly more granular grouping
107
+ - @concentric@ := an implementation of "Concentric CSS":https://github.com/brandon-rhodes/Concentric-CSS
108
+ - @personal@ := my personal ordering, just cuz…
109
+
110
+
111
+ h3. Specifying your own configuration
112
+
113
+ Groups are specified as a YAML hash, in the order in which they should appear in your SASS. Each group *must* have a @properties@ member, containing an array of properties that may appear in this group.
114
+
115
+ <pre><code lang="yaml">groups:
116
+ tables:
117
+ properties:
118
+ - table-layout
119
+ - border-collapse
120
+ - empty-cells</code></pre>
121
+
122
+ Specifies a group called @tables@, which may contain @table-layout@, @border-collapse@ and @empty-cells@ properties.
123
+
124
+ h4. Wildcard properties
125
+
126
+ In cases where a number of properties may have the same prefix, wildcard properties may used instead.
127
+ Thus, the following group definitions are equivalent.
128
+
129
+ <pre><code lang="yaml">groups:
130
+ text:
131
+ properties:
132
+ - font
133
+ - font-size
134
+ - font-family
135
+ - font-style
136
+ text_two:
137
+ properties:
138
+ - font*</code></pre>
139
+
140
+ Naturally, you might want to use this functionality carefully…
141
+
142
+ h4. Overriding defaults
143
+
144
+ In some cases, you may wish to override the default linting options. This can be done by adding the appropriate option to the group hash:
145
+
146
+ <pre><code lang="yaml">groups:
147
+ tables:
148
+ max_no_space: 1
149
+ properties:
150
+ - table-layout
151
+ - border-collapse
152
+ - empty-cells</code></pre>
153
+
154
+ This defines a @tables@ group as earlier, but requires a space around it at all times.
155
+
156
+ h2. Why?
157
+
158
+ I’ve written a "blog post":https://jonpearse.net/articles/2016/07/on-linting-and-bringing-order-to-sass about this, but the short version is that I really don’t get on with SCSS-Lint’s default @PropertySortOrder@ linter =)
159
+
160
+ h2. Version History
161
+
162
+ h3. 1.1.2 _(March 18th, 2017)_
163
+
164
+ * eventually pushing this up to RubyGems
165
+
166
+ h3. 1.1.1 _(July 15th, 2016)_
167
+
168
+ * fixing dumb typoes in the readme
169
+
170
+ h3. 1.1.0 _(July 15th, 2016)_
171
+
172
+ * improved hint messages to be somewhat more useful to the average developer
173
+
174
+ h3. 1.0.0 _(June 12th, 2016)_
175
+
176
+ * initial release
177
+
178
+ h2. Mandatory sales pitch
179
+
180
+ When I’m not hacking at random things, I’m a freelance web developer specialising in all things front-end, based in the beautiful city of Cardiff, UK.
181
+ I’m usually kept fairly busy with project work, but I’m always on the lookout for new people to do cool stuff with. "Drop me a line":mailto:hello@jonpearse.net – I’d love to hear from you!
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,82 @@
1
+ # Concentric CSS [ http://rhodesmill.org/brandon/2011/concentric-css/ ]
2
+ #
3
+ # This is roughly based on SCSS-Lint‘s specification, found at
4
+ # [ https://github.com/brigade/scss-lint/blob/master/data/property-sort-orders/concentric.txt ]
5
+ groups:
6
+ directions:
7
+ - display
8
+ - position
9
+ - top
10
+ - right
11
+ - bottom
12
+ - left
13
+
14
+ columns:
15
+ - columns
16
+ - column*
17
+
18
+ float:
19
+ - float
20
+ - clear
21
+
22
+ transform:
23
+ - transform*
24
+ - transition
25
+ - animation*
26
+
27
+ visibility:
28
+ - visibility
29
+ - opacity
30
+ - z-index
31
+
32
+ box:
33
+ - margin*
34
+ - outline
35
+ - border
36
+ - border-style
37
+ - border-color
38
+ - border-radius
39
+ - border-width
40
+ - border-image
41
+ - border-top*
42
+ - border-right*
43
+ - border-bottom*
44
+ - border-left*
45
+ - box-shadow
46
+ - background*
47
+ - cursor
48
+ - padding*
49
+
50
+ dimensions:
51
+ - width
52
+ - min-width
53
+ - max-width
54
+ - height
55
+ - min-height
56
+ - max-height
57
+ - overflow*
58
+
59
+ lists:
60
+ - list-style*
61
+
62
+ tables:
63
+ - caption-side
64
+ - table-layout
65
+ - border-collapse
66
+ - border-spacing
67
+ - empty-cells
68
+
69
+ content:
70
+ - vertical-align
71
+ - text*
72
+ - line-height
73
+ - word-spacing
74
+ - letter-spacing
75
+ - white-space
76
+ - color
77
+ - font*
78
+
79
+ generated:
80
+ - content
81
+ - quotes
82
+ - counter* # it strikes me that this should be in lists, but it’s generated, so…
@@ -0,0 +1,151 @@
1
+ # This is a variation on SMACSS that specifies a more granular grouping of properties, rather than the five Jonathan
2
+ # Snook proposes. YMMV =)
3
+ groups:
4
+ box-position:
5
+ - display
6
+ - position
7
+ - top
8
+ - right
9
+ - bottom
10
+ - left
11
+
12
+ flex:
13
+ - flex
14
+ - flex-basis
15
+ - flex-direction
16
+ - flex-flow
17
+ - flex-grow
18
+ - flex-shrink
19
+ - flex-wrap
20
+ - align-content
21
+ - align-items
22
+ - align-self
23
+ - justify-content
24
+ - order
25
+
26
+ box-dimensions:
27
+ - width
28
+ - min-width
29
+ - max-width
30
+ - height
31
+ - min-height
32
+ - max-height
33
+ - margin
34
+ - margin-top
35
+ - margin-right
36
+ - margin-bottom
37
+ - margin-left
38
+ - padding
39
+ - padding-top
40
+ - padding-right
41
+ - padding-bottom
42
+ - padding-left
43
+
44
+ float:
45
+ - float
46
+ - clear
47
+ - clip
48
+
49
+ columns:
50
+ - columns
51
+ - column-gap
52
+ - column-fill
53
+ - column-rule
54
+ - column-span
55
+ - column-count
56
+ - column-width
57
+
58
+ transform:
59
+ - transform
60
+ - transform-box
61
+ - transform-origin
62
+ - transform-style
63
+
64
+ transition:
65
+ - transition
66
+ - transition-delay
67
+ - transition-duration
68
+ - transition-property
69
+ - transition-timing-function
70
+
71
+ border:
72
+ - border
73
+ - border-top
74
+ - border-right
75
+ - border-bottom
76
+ - border-left
77
+ - border-width
78
+ - border-top-width
79
+ - border-right-width
80
+ - border-bottom-width
81
+ - border-left-width
82
+ - border-style
83
+ - border-top-style
84
+ - border-right-style
85
+ - border-bottom-style
86
+ - border-left-style
87
+ - border-radius
88
+ - border-top-left-radius
89
+ - border-top-right-radius
90
+ - border-bottom-left-radius
91
+ - border-bottom-right-radius
92
+ - border-color
93
+ - border-top-color
94
+ - border-right-color
95
+ - border-bottom-color
96
+ - border-left-color
97
+ - outline
98
+ - outline-color
99
+ - outline-offset
100
+ - outline-style
101
+ - outline-width
102
+
103
+ background:
104
+ - background
105
+ - background-attachment
106
+ - background-clip
107
+ - background-color
108
+ - background-image
109
+ - background-repeat
110
+ - background-position
111
+ - background-size
112
+
113
+ text:
114
+ - color
115
+ - font
116
+ - font-family
117
+ - font-size
118
+ - font-smoothing
119
+ - font-style
120
+ - font-variant
121
+ - font-weight
122
+ - letter-spacing
123
+ - line-height
124
+ - list-style
125
+ - text-align
126
+ - text-decoration
127
+ - text-indent
128
+ - text-overflow
129
+ - text-rendering
130
+ - text-shadow
131
+ - text-transform
132
+ - text-wrap
133
+ - white-space
134
+ - word-spacing
135
+
136
+ other:
137
+ - border-collapse
138
+ - border-spacing
139
+ - box-shadow
140
+ - caption-side
141
+ - content
142
+ - cursor
143
+ - empty-cells
144
+ - opacity
145
+ - overflow
146
+ - quotes
147
+ - speak
148
+ - table-layout
149
+ - vertical-align
150
+ - visibility
151
+ - z-index
@@ -0,0 +1,100 @@
1
+ # This is my own personal preference, included [a] to make my life easier, and [b] in case anyone is interested.
2
+ #
3
+ # Note that this is very much an ongoing process and may change at any time as I tweak and change things. Let me know
4
+ # what you think!
5
+ groups:
6
+ display:
7
+ properties:
8
+ - position
9
+ - display
10
+ - visibility
11
+ - overflow*
12
+ - float
13
+ - clear
14
+ - content
15
+ - box-sizing
16
+
17
+ flex-parent:
18
+ properties:
19
+ - flex-direction
20
+ - flex-wrap
21
+ - flex-flow
22
+ - justify-content
23
+ - align-items
24
+ - align-content
25
+
26
+ flex-child:
27
+ properties:
28
+ - flex
29
+ - order
30
+ - flex-grow
31
+ - flex-shrink
32
+ - flex-basis
33
+ - align-self
34
+
35
+ tables:
36
+ max_no_space: 1
37
+ properties:
38
+ - table-layout
39
+ - border-collapse
40
+ - empty-cells
41
+
42
+ dimensional:
43
+ properties:
44
+ - top
45
+ - left
46
+ - bottom
47
+ - right
48
+ - height
49
+ - min-height
50
+ - max-height
51
+ - width
52
+ - min-width
53
+ - max-width
54
+ - padding*
55
+ - margin*
56
+ - transform
57
+
58
+ presentational:
59
+ properties:
60
+ - outline*
61
+ - border
62
+ - border-style
63
+ - border-color
64
+ - border-radius
65
+ - border-width
66
+ - border-image
67
+ - border-top*
68
+ - border-right*
69
+ - border-bottom*
70
+ - border-left*
71
+ - background*
72
+ - opacity
73
+ - z-index
74
+ - color
75
+ - box-shadow
76
+ - filter
77
+
78
+ lists:
79
+ space_around: false
80
+ properties:
81
+ - counter*
82
+ - list-style*
83
+
84
+ text:
85
+ properties:
86
+ - font*
87
+ - line-height
88
+ - letter-spacing
89
+ - text-align
90
+ - text-decoration
91
+ - text-indent
92
+ - text-transform
93
+ - text-shadow
94
+ - white-space
95
+ - content
96
+
97
+ interaction:
98
+ properties:
99
+ - transition
100
+ - animation
data/data/smacss.yaml ADDED
@@ -0,0 +1,142 @@
1
+ # Note: whilst SMACSS defines groups, it doesn’t seem overly fussy about the order of properties within those groups.
2
+ # I could enforce some kind of subgrouping, but… that‘s not what SMACSS says and I don’t want to enforce something
3
+ # non-standard.
4
+ #
5
+ # You may wish to adapt this style to your own personal tastes =)
6
+ groups:
7
+ box:
8
+ - display
9
+ - position
10
+ - top
11
+ - right
12
+ - bottom
13
+ - left
14
+ - flex
15
+ - flex-basis
16
+ - flex-direction
17
+ - flex-flow
18
+ - flex-grow
19
+ - flex-shrink
20
+ - flex-wrap
21
+ - align-content
22
+ - align-items
23
+ - align-self
24
+ - justify-content
25
+ - order
26
+ - width
27
+ - min-width
28
+ - max-width
29
+ - height
30
+ - min-height
31
+ - max-height
32
+ - margin
33
+ - margin-top
34
+ - margin-right
35
+ - margin-bottom
36
+ - margin-left
37
+ - padding
38
+ - padding-top
39
+ - padding-right
40
+ - padding-bottom
41
+ - padding-left
42
+ - float
43
+ - clear
44
+ - clip
45
+ - columns
46
+ - column-gap
47
+ - column-fill
48
+ - column-rule
49
+ - column-span
50
+ - column-count
51
+ - column-width
52
+ - transform
53
+ - transform-box
54
+ - transform-origin
55
+ - transform-style
56
+ - transition
57
+ - transition-delay
58
+ - transition-duration
59
+ - transition-property
60
+ - transition-timing-function
61
+
62
+ border:
63
+ - border
64
+ - border-top
65
+ - border-right
66
+ - border-bottom
67
+ - border-left
68
+ - border-width
69
+ - border-top-width
70
+ - border-right-width
71
+ - border-bottom-width
72
+ - border-left-width
73
+ - border-style
74
+ - border-top-style
75
+ - border-right-style
76
+ - border-bottom-style
77
+ - border-left-style
78
+ - border-radius
79
+ - border-top-left-radius
80
+ - border-top-right-radius
81
+ - border-bottom-left-radius
82
+ - border-bottom-right-radius
83
+ - border-color
84
+ - border-top-color
85
+ - border-right-color
86
+ - border-bottom-color
87
+ - border-left-color
88
+ - outline
89
+ - outline-color
90
+ - outline-offset
91
+ - outline-style
92
+ - outline-width
93
+
94
+ background:
95
+ - background
96
+ - background-attachment
97
+ - background-clip
98
+ - background-color
99
+ - background-image
100
+ - background-repeat
101
+ - background-position
102
+ - background-size
103
+
104
+ text:
105
+ - color
106
+ - font
107
+ - font-family
108
+ - font-size
109
+ - font-smoothing
110
+ - font-style
111
+ - font-variant
112
+ - font-weight
113
+ - letter-spacing
114
+ - line-height
115
+ - list-style
116
+ - text-align
117
+ - text-decoration
118
+ - text-indent
119
+ - text-overflow
120
+ - text-rendering
121
+ - text-shadow
122
+ - text-transform
123
+ - text-wrap
124
+ - white-space
125
+ - word-spacing
126
+
127
+ other:
128
+ - border-collapse
129
+ - border-spacing
130
+ - box-shadow
131
+ - caption-side
132
+ - content
133
+ - cursor
134
+ - empty-cells
135
+ - opacity
136
+ - overflow
137
+ - quotes
138
+ - speak
139
+ - table-layout
140
+ - vertical-align
141
+ - visibility
142
+ - z-index
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'grouped_property_scss_linter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "grouped_property_scss_linter"
8
+ spec.version = GroupedPropertyScssLinter::VERSION
9
+ spec.authors = ["Jon Pearse"]
10
+ spec.email = ["jon@jonpearse.net"]
11
+ spec.summary = "SCSS Lint plugin"
12
+ spec.description = "Plugin for SCSS lint that lints the order of properties based on fuzzy groups"
13
+ spec.homepage = "https://github.com/jonpearse/grouped_property_scss_linter"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_development_dependency "bundler", "~> 1.6"
20
+ spec.add_development_dependency "rake", '~> 0'
21
+
22
+ spec.add_dependency 'scss_lint', '~> 0'
23
+ end
data/lib/ext/string.rb ADDED
@@ -0,0 +1,9 @@
1
+ class String
2
+
3
+ def bold
4
+
5
+ "\e[1m#{self}\e[0m"
6
+
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ require "grouped_property_scss_linter/version"
2
+ require "grouped_property_scss_linter/grouped_property_order"
3
+ require "ext/string"
4
+
5
+ module GroupedPropertyScssLinter
6
+
7
+ STYLES_DIR = File.realpath(File.join(File.dirname(__FILE__), '..', 'data')).freeze
8
+
9
+ end
@@ -0,0 +1,310 @@
1
+ module SCSSLint
2
+ class Linter::GroupedPropertyOrder < Linter
3
+ include LinterRegistry
4
+
5
+ # Called when the linter is fired up on a document. Acts as a pseudo-constructor
6
+ def visit_root( node )
7
+
8
+ # get configured order
9
+ @configured_groups = get_order_from_conf
10
+
11
+ # and map things around
12
+ @groups = []
13
+ @property_to_group = {}
14
+ count = 0
15
+ @configured_groups.each_pair do |name, group|
16
+ @groups.push name
17
+ group['properties'].each do |property|
18
+ @property_to_group[property] = { name: name, idx: count }
19
+ end
20
+ count = count+1
21
+ end
22
+
23
+ yield
24
+
25
+ end
26
+
27
+ # Logic that actually performs order
28
+ def check_order( node )
29
+
30
+ # 1. get a list of properties we can sort
31
+ sortable_properties = node.children.select do |child|
32
+ child.is_a? Sass::Tree::PropNode
33
+ end
34
+
35
+ # 2. group things
36
+ grouped_properties = {}
37
+ props = sortable_properties.map do |prop|
38
+
39
+ # simplify the name a little
40
+ name = prop.name.join
41
+
42
+ # attempt to match the name
43
+ group = find_match_for_property name
44
+
45
+ # if it didn’t find anything, move on
46
+ next if group.nil?
47
+
48
+ # if there’s no existing group
49
+ unless grouped_properties.key? group[:name]
50
+ grouped_properties[group[:name]] = { first: 1.0/0, last: 0, props: [] }
51
+ end
52
+
53
+ # build a concat
54
+ concat = { name: name, node: prop, group: group[:name], line: prop.line, group_idx: group[:idx] }
55
+
56
+ # drop things on
57
+ grouped_properties[group[:name]][:first] = [grouped_properties[group[:name]][:first], prop.line].min
58
+ grouped_properties[group[:name]][:last] = [grouped_properties[group[:name]][:last], prop.line].max
59
+ grouped_properties[group[:name]][:props] << concat
60
+
61
+ concat
62
+
63
+ end
64
+ props.compact!
65
+
66
+ # 3. call down
67
+ unless grouped_properties.empty?
68
+ check_sort_order props, grouped_properties
69
+ end
70
+
71
+ # 4. yield so we can process children
72
+ yield
73
+
74
+ end
75
+
76
+ # alias things out
77
+ alias visit_media check_order
78
+ alias visit_mixin check_order
79
+ alias visit_rule check_order
80
+ alias visit_prop check_order
81
+
82
+ def visit_if(node, &block)
83
+ check_order(node, &block)
84
+ visit(node.else) if node.else
85
+ end
86
+
87
+ private
88
+
89
+ # Acquires configuration and populates out a group array
90
+ def get_order_from_conf
91
+
92
+ # 1. acquire defaults + default them, just in case
93
+ defaults = config['defaults']
94
+ defaults['space_around'] |= true
95
+ defaults['max_no_space'] |= 3
96
+
97
+ # 2, acquire groups
98
+ groups = config['groups'] || load_groups_from_style
99
+
100
+ # 3. if it failed, bail
101
+ raise 'No groups configured' if groups.nil?
102
+
103
+ # 4. munge
104
+ groups.update(groups) do |name, group|
105
+
106
+ # a. if it’s an array, cast it
107
+ group = { 'properties' => group } if group.is_a? Array
108
+
109
+ # b. merge in some defaults
110
+ group['space_around'] = defaults['space_around'] if group['space_around'].nil?
111
+ group['max_no_space'] ||= defaults['max_no_space']
112
+
113
+ # c. return
114
+ group
115
+
116
+ end
117
+
118
+ groups
119
+
120
+ end
121
+
122
+ # Loads a group from a configured style
123
+ def load_groups_from_style
124
+
125
+ # 0. if the style is blank/empty…
126
+ (raise 'No style specified' and return) if config['style'].empty?
127
+
128
+ # 1. attempt to find the file
129
+ data_filename = File.join(GroupedPropertyScssLinter::STYLES_DIR, "#{config['style']}.yaml")
130
+
131
+ # 2. does it exist
132
+ (raise "No style ‘#{config['style']}’ found" and return) unless File.exists? data_filename
133
+
134
+ # 3. can we read it
135
+ (raise "Cannot read style ‘#{config['style']}’" and return) unless File.readable? data_filename
136
+
137
+ # 4. open
138
+ style_config = YAML.load_file data_filename
139
+
140
+ # 5. barf?
141
+ (raise "Bad style file found for ‘#{config['style']}’" and return) if style_config.nil? or style_config['groups'].nil?
142
+
143
+ style_config['groups']
144
+ end
145
+
146
+ # Finds a matching group for a specified property
147
+ def find_match_for_property( prop )
148
+
149
+ # sanitise the name by removing any browser prefixes
150
+ prop = prop.gsub(/^(-\w+(-osx)?-)?/, '')
151
+
152
+ # iteratively remove hyphens from the property…
153
+ while prop =~ /\-/
154
+
155
+ # if we know about this property or its splatted variety…
156
+ if @property_to_group.key? prop or @property_to_group.key? prop+'*'
157
+
158
+ return @property_to_group[prop] || @property_to_group[prop+'*']
159
+
160
+ end
161
+
162
+ prop.gsub! /\-(\w+)$/, ''
163
+
164
+ end
165
+
166
+ # finally…
167
+ if @property_to_group.key? prop or @property_to_group.key? prop+'*'
168
+
169
+ return @property_to_group[prop] || @property_to_group[prop+'*']
170
+
171
+ end
172
+
173
+ nil
174
+
175
+ end
176
+
177
+ def check_sort_order( props, grouped )
178
+
179
+ # get stats on grouped version
180
+ grouped.each_value do |group|
181
+
182
+ # number of properties
183
+ group[:num] = group[:props].length
184
+ group[:delta] = group[:last] - group[:first]
185
+
186
+ end
187
+
188
+ # quick duck-type
189
+ quick_check_order props, grouped
190
+
191
+ # if we’re checking whitespace, do so
192
+ check_whitespace( grouped ) unless grouped.length < 2
193
+
194
+ end
195
+
196
+ def quick_check_order( props, grouped )
197
+
198
+ current_group = 0
199
+ good = true
200
+
201
+ props.each do |prop|
202
+
203
+ # if it’s the current group, move on
204
+ next if prop[:group] == @groups[current_group]
205
+
206
+ # find an index
207
+ idx = @groups.index prop[:group]
208
+
209
+ # if it’s less-than, error out
210
+ if idx < current_group
211
+
212
+ ext = config['extended_hinting'] ? " (assigned group ‘#{prop[:group].bold}’, found group ‘#{@groups[current_group].bold}’)" : ""
213
+
214
+ add_lint prop[:node], "property ‘#{prop[:name].bold}’ should be #{hint_text_for(prop, grouped, props)}#{ext}"
215
+ good = false
216
+ else
217
+ current_group = idx
218
+ end
219
+
220
+ end
221
+
222
+ good
223
+
224
+ end
225
+
226
+ def check_whitespace( grouped )
227
+
228
+ # get a quick handle on all the groups we’ve found
229
+ detected_groups = grouped.keys
230
+
231
+ # iterate through
232
+ curr_idx = 0
233
+ grouped.each_pair do |name, current|
234
+
235
+ # get a configuration
236
+ group_conf = @configured_groups[name]
237
+
238
+ # if we don’t care about space, bail
239
+ (curr_idx += 1 and next) unless group_conf['space_around']
240
+
241
+ # similarly, if this group is too small to trigger spacing, bounce
242
+ (curr_idx += 1 and next)unless current[:props].length > group_conf['max_no_space']
243
+
244
+ # set some easy references
245
+ next_group = detected_groups.length > curr_idx ? grouped[detected_groups[curr_idx + 1]] : nil
246
+ prev_group = curr_idx > 0 ? grouped[detected_groups[curr_idx - 1]] : nil
247
+
248
+ # if there’s something after us, and there’s no space
249
+ if !next_group.nil? and ((next_group[:first] - current[:last]) < 2)
250
+
251
+ # raise a lint error
252
+ add_lint current[:props].last[:node], "Must be at least one empty line after ‘#{current[:props].last[:name]}’"
253
+
254
+ # also, flag the next group so we don’t catch it next time ‘round
255
+ next_group[:raised] = true
256
+ end
257
+
258
+ # if there’s something before us, and there’s no space…
259
+ if !prev_group.nil? and ((current[:first] - prev_group[:last]) < 2) and current[:raised].nil?
260
+
261
+ # raise a lint error
262
+ add_lint current[:props].first[:node], "Must be at least one empty line before ‘#{current[:props].first[:name]}’"
263
+
264
+ end
265
+
266
+ # finally, increment
267
+ curr_idx += 1
268
+
269
+ end
270
+ end
271
+
272
+ def hint_text_for( prop, grouped_props, context )
273
+
274
+ # get target group
275
+ dst_group = prop[:group]
276
+
277
+ # if we know about the group…
278
+ if grouped_props.key? dst_group
279
+
280
+ # get the first property of the current group
281
+ dst_prop = grouped_props[dst_group][:props].first
282
+
283
+ # if it’s a different property, return
284
+ return "after ‘#{dst_prop[:name].bold}’" if dst_prop != prop
285
+ end
286
+
287
+ # either our offending property is the sole member of a group, or it’s very lost… so look for a previous marker
288
+ curr_idx = prop[:group_idx]
289
+ while curr_idx > 0
290
+
291
+ # decrement and reset
292
+ curr_idx = curr_idx - 1
293
+ dst_group = @groups[curr_idx]
294
+
295
+ # look
296
+ if grouped_props.key? dst_group
297
+
298
+ # get the _last_ property of the group
299
+ dst_prop = grouped_props[dst_group][:props].last
300
+
301
+ # and return
302
+ return "after ‘#{dst_prop[:name].bold}’"
303
+ end
304
+ end
305
+
306
+ # otherwise, it probably belongs right at the start
307
+ "before ‘#{context.first[:name].bold}’"
308
+ end
309
+ end
310
+ end
@@ -0,0 +1,3 @@
1
+ module GroupedPropertyScssLinter
2
+ VERSION = "1.1.3"
3
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grouped_property_scss_linter
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Jon Pearse
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: scss_lint
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Plugin for SCSS lint that lints the order of properties based on fuzzy
56
+ groups
57
+ email:
58
+ - jon@jonpearse.net
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".scss-lint.yml"
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.textile
68
+ - Rakefile
69
+ - data/concentric.yaml
70
+ - data/grouped-smacss.yaml
71
+ - data/personal.yaml
72
+ - data/smacss.yaml
73
+ - grouped_property_scss_linter.gemspec
74
+ - lib/ext/string.rb
75
+ - lib/grouped_property_scss_linter.rb
76
+ - lib/grouped_property_scss_linter/grouped_property_order.rb
77
+ - lib/grouped_property_scss_linter/version.rb
78
+ homepage: https://github.com/jonpearse/grouped_property_scss_linter
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.6.10
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: SCSS Lint plugin
102
+ test_files: []