csscss 0.0.1 → 0.1.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.
- data/.gitignore +0 -1
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +39 -0
- data/README.md +47 -12
- data/bin/csscss +0 -1
- data/csscss.gemspec +2 -3
- data/lib/csscss/cli.rb +10 -1
- data/lib/csscss/json_reporter.rb +17 -0
- data/lib/csscss/parser/background.rb +72 -0
- data/lib/csscss/parser/base.rb +13 -0
- data/lib/csscss/parser/border.rb +45 -0
- data/lib/csscss/parser/border_color.rb +41 -0
- data/lib/csscss/parser/border_side.rb +91 -0
- data/lib/csscss/parser/border_style.rb +41 -0
- data/lib/csscss/parser/border_width.rb +37 -0
- data/lib/csscss/parser/color.rb +53 -0
- data/lib/csscss/parser/common.rb +86 -0
- data/lib/csscss/parser/css.rb +88 -0
- data/lib/csscss/parser/font.rb +96 -0
- data/lib/csscss/parser/list_style.rb +44 -0
- data/lib/csscss/parser/margin.rb +32 -0
- data/lib/csscss/parser/multi_side_transformer.rb +47 -0
- data/lib/csscss/parser/outline.rb +45 -0
- data/lib/csscss/parser/padding.rb +32 -0
- data/lib/csscss/parslet_optimizations.rb +77 -0
- data/lib/csscss/redundancy_analyzer.rb +75 -8
- data/lib/csscss/reporter.rb +2 -4
- data/lib/csscss/types.rb +77 -2
- data/lib/csscss/version.rb +1 -1
- data/lib/csscss.rb +22 -1
- data/test/csscss/json_reporter_test.rb +34 -0
- data/test/csscss/parser/background_test.rb +57 -0
- data/test/csscss/parser/border_color_test.rb +30 -0
- data/test/csscss/parser/border_side_test.rb +44 -0
- data/test/csscss/parser/border_style_test.rb +30 -0
- data/test/csscss/parser/border_test.rb +31 -0
- data/test/csscss/parser/border_width_test.rb +30 -0
- data/test/csscss/parser/color_test.rb +51 -0
- data/test/csscss/parser/common_test.rb +130 -0
- data/test/csscss/parser/css_test.rb +133 -0
- data/test/csscss/parser/font_test.rb +43 -0
- data/test/csscss/parser/list_style_test.rb +28 -0
- data/test/csscss/parser/margin_test.rb +50 -0
- data/test/csscss/parser/outline_test.rb +26 -0
- data/test/csscss/parser/padding_test.rb +50 -0
- data/test/csscss/redundancy_analyzer_test.rb +126 -4
- data/test/csscss/reporter_test.rb +4 -2
- data/test/csscss/types_test.rb +73 -0
- data/test/just_parse.rb +8 -0
- data/test/test_helper.rb +49 -6
- metadata +61 -23
- data/.rspec.default +0 -1
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
csscss (0.1.0)
|
5
|
+
parslet (~> 1.5)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
blankslate (2.1.2.4)
|
11
|
+
columnize (0.3.6)
|
12
|
+
debugger (1.5.0)
|
13
|
+
columnize (>= 0.3.1)
|
14
|
+
debugger-linecache (~> 1.2.0)
|
15
|
+
debugger-ruby_core_source (~> 1.2.0)
|
16
|
+
debugger-linecache (1.2.0)
|
17
|
+
debugger-ruby_core_source (1.2.0)
|
18
|
+
m (1.3.1)
|
19
|
+
method_source (>= 0.6.7)
|
20
|
+
rake (>= 0.9.2.2)
|
21
|
+
method_source (0.8.1)
|
22
|
+
minitest (2.12.1)
|
23
|
+
minitest-rg (1.1.0)
|
24
|
+
parslet (1.5.0)
|
25
|
+
blankslate (~> 2.0)
|
26
|
+
rake (10.0.3)
|
27
|
+
ruby-prof (0.13.0)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
csscss!
|
34
|
+
debugger
|
35
|
+
m
|
36
|
+
minitest
|
37
|
+
minitest-rg
|
38
|
+
rake
|
39
|
+
ruby-prof
|
data/README.md
CHANGED
@@ -1,25 +1,60 @@
|
|
1
|
-
# Csscss
|
2
|
-
|
3
1
|
[](https://travis-ci.org/zmoazeni/csscss)
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
## What is it? ##
|
4
|
+
|
5
|
+
csscss will parse any CSS files you give it and let you know which
|
6
|
+
rulesets have duplicated declarations.
|
7
|
+
|
8
|
+
## What is it for? ##
|
9
|
+
|
10
|
+
One of the best strategies for me to maintain CSS is to reduce
|
11
|
+
duplication as much as possible. It's not a silver bullet, but it sure
|
12
|
+
helps.
|
8
13
|
|
9
|
-
|
14
|
+
To do that, you need to have all the rulesets in your head at all times.
|
15
|
+
That's hard, csscss is easy. Let it tell you what is redundant.
|
10
16
|
|
11
|
-
|
17
|
+
## How do I use it? ##
|
18
|
+
|
19
|
+
First you need to install it. It is currently packaged as a ruby gem:
|
12
20
|
|
13
21
|
$ gem install csscss
|
14
22
|
|
15
|
-
|
23
|
+
Then you can run it in at the command line against CSS files.
|
24
|
+
|
25
|
+
$ csscss path/to/styles.css path/to/other-styles.css
|
26
|
+
|
27
|
+
Run it in a verbose mode to see all the duplicated styles.
|
28
|
+
|
29
|
+
$ csscss -v path/to/styles.css
|
30
|
+
|
31
|
+
You can also choose a minimum number of matches, which will ignore any
|
32
|
+
rulesets that have fewer matches.
|
33
|
+
|
34
|
+
$ csscss -n 10 -v path/to/style.css # ignores rulesets with < 10 matches
|
35
|
+
|
36
|
+
## I found bugs ##
|
37
|
+
|
38
|
+
This is still a new and evolving project. I heartily welcome feedback.
|
39
|
+
If you find any issues, please report them on
|
40
|
+
[github](https://github.com/zmoazeni/csscss/issues).
|
41
|
+
|
42
|
+
Please include the smallest CSS snippet to describe the issue and the
|
43
|
+
output you expect to see.
|
44
|
+
|
45
|
+
## Who are you? ##
|
46
|
+
|
47
|
+
My name is [Zach Moazeni](https://twitter.com/zmoazeni). I work for [an
|
48
|
+
awesome company](http://www.getharvest.com/), which [is
|
49
|
+
hiring!](http://www.getharvest.com/careers).
|
16
50
|
|
17
|
-
|
51
|
+
## I'm a dev, I can help ##
|
18
52
|
|
19
|
-
|
53
|
+
Awesome! Thanks! Here are the steps I ask:
|
20
54
|
|
21
55
|
1. Fork it
|
22
56
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
23
57
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
24
|
-
4.
|
25
|
-
5.
|
58
|
+
4. Make sure the tests pass (`bundle exec rake test`)
|
59
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
60
|
+
6. Create new Pull Request
|
data/bin/csscss
CHANGED
data/csscss.gemspec
CHANGED
@@ -9,14 +9,13 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.authors = ["Zach Moazeni"]
|
10
10
|
gem.email = ["zach.moazeni@gmail.com"]
|
11
11
|
gem.description = %q{A CSS redundancy analyzer that analyzes redundancy.}
|
12
|
-
gem.summary = %q{
|
13
|
-
gem.homepage = ""
|
12
|
+
gem.summary = %q{csscss will parse any CSS files you give it and let you know which rulesets have duplicated declarations.}
|
13
|
+
gem.homepage = "http://zmoazeni.github.com/csscss/"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.add_dependency "csspool", "~> 3.0"
|
21
20
|
gem.add_dependency "parslet", "~> 1.5"
|
22
21
|
end
|
data/lib/csscss/cli.rb
CHANGED
@@ -27,7 +27,16 @@ module Csscss
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
if @json
|
31
|
+
puts JSONReporter.new(combined_redundancies).report
|
32
|
+
else
|
33
|
+
puts Reporter.new(combined_redundancies).report(@verbose)
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue Parslet::ParseFailed => e
|
37
|
+
puts "Had a problem parsing the css"
|
38
|
+
puts e.cause.ascii_tree
|
39
|
+
exit 1
|
31
40
|
end
|
32
41
|
|
33
42
|
def parse(argv)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Csscss
|
2
|
+
class JSONReporter
|
3
|
+
def initialize(redundancies)
|
4
|
+
@redundancies = redundancies
|
5
|
+
end
|
6
|
+
|
7
|
+
def report
|
8
|
+
JSON.dump(@redundancies.map {|selector_groups, declarations|
|
9
|
+
{
|
10
|
+
"selectors" => selector_groups.map(&:to_s),
|
11
|
+
"count" => declarations.count,
|
12
|
+
"declarations" => declarations.map(&:to_s)
|
13
|
+
}
|
14
|
+
})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module Background
|
4
|
+
extend Parser::Base
|
5
|
+
|
6
|
+
class Parser < Parslet::Parser
|
7
|
+
include Color
|
8
|
+
|
9
|
+
rule(:bg_color) { color | symbol("inherit") }
|
10
|
+
rule(:bg_image) { (url | symbol("none") | symbol("inherit")).as(:image_literal) }
|
11
|
+
rule(:bg_repeat) { symbol_list(%w(repeat-x repeat-y repeat no-repeat inherit)).as(:repeat) }
|
12
|
+
rule(:bg_attachment) { symbol_list(%w(scroll fixed inherit)).as(:attachment) }
|
13
|
+
|
14
|
+
rule(:bg_position) {
|
15
|
+
lcr_symbols = symbol_list(%w(left center right))
|
16
|
+
tcb_symbols = symbol_list(%w(top center bottom))
|
17
|
+
|
18
|
+
(symbol("inherit") | (
|
19
|
+
lcr = (percent | length | lcr_symbols)
|
20
|
+
tcb = (percent | length | tcb_symbols)
|
21
|
+
|
22
|
+
lcr >> tcb | lcr | tcb
|
23
|
+
)).as(:position)
|
24
|
+
}
|
25
|
+
|
26
|
+
rule(:background) {
|
27
|
+
(
|
28
|
+
symbol("inherit") >> eof | (
|
29
|
+
bg_color.maybe.as(:bg_color) >>
|
30
|
+
bg_image.maybe.as(:bg_image) >>
|
31
|
+
bg_repeat.maybe.as(:bg_repeat) >>
|
32
|
+
bg_attachment.maybe.as(:bg_attachment) >>
|
33
|
+
bg_position.maybe.as(:bg_position)
|
34
|
+
)
|
35
|
+
).as(:background)
|
36
|
+
}
|
37
|
+
root(:background)
|
38
|
+
end
|
39
|
+
|
40
|
+
class Transformer < Parslet::Transform
|
41
|
+
@property = :background_color
|
42
|
+
extend Color::Transformer
|
43
|
+
|
44
|
+
rule(image_literal:simple(:value)) {Declaration.from_parser("background-image", value) }
|
45
|
+
|
46
|
+
rule(:repeat => simple(:repeat)) {
|
47
|
+
Declaration.from_parser("background-repeat", repeat)
|
48
|
+
}
|
49
|
+
|
50
|
+
rule(:attachment => simple(:attachment)) {
|
51
|
+
Declaration.from_parser("background-attachment", attachment)
|
52
|
+
}
|
53
|
+
|
54
|
+
rule(:position => simple(:position)) {
|
55
|
+
Declaration.from_parser("background-position", position)
|
56
|
+
}
|
57
|
+
|
58
|
+
rule(:background => simple(:inherit)) {[]}
|
59
|
+
|
60
|
+
rule(background: {
|
61
|
+
bg_color:simple(:color),
|
62
|
+
bg_image:simple(:url),
|
63
|
+
bg_repeat:simple(:repeat),
|
64
|
+
bg_attachment:simple(:attachment),
|
65
|
+
bg_position:simple(:position)
|
66
|
+
}) {
|
67
|
+
[color, url, repeat, attachment, position].compact
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module Border
|
4
|
+
extend Parser::Base
|
5
|
+
|
6
|
+
class Parser < Parslet::Parser
|
7
|
+
include Color
|
8
|
+
|
9
|
+
rule(:border_side) { BorderSide::Parser.new(:top).border_side_anonymous }
|
10
|
+
|
11
|
+
rule(:border) {
|
12
|
+
(
|
13
|
+
symbol("inherit") >> eof |
|
14
|
+
border_side.maybe.as(:side)
|
15
|
+
).as(:border)
|
16
|
+
}
|
17
|
+
|
18
|
+
root(:border)
|
19
|
+
end
|
20
|
+
|
21
|
+
class Transformer < Parslet::Transform
|
22
|
+
extend Color::Transformer
|
23
|
+
extend Color::PlainColorValue
|
24
|
+
extend BorderSide::Transformer::Helpers
|
25
|
+
|
26
|
+
rule(border: simple(:inherit)) {[]}
|
27
|
+
rule(border: {
|
28
|
+
side: {
|
29
|
+
width:simple(:width),
|
30
|
+
style:simple(:style),
|
31
|
+
color:simple(:color)
|
32
|
+
}
|
33
|
+
}) {|context|
|
34
|
+
[].tap do |declarations|
|
35
|
+
[:top, :right, :bottom, :left].each do |side|
|
36
|
+
declarations << transform_side(side, context)
|
37
|
+
end
|
38
|
+
|
39
|
+
declarations.flatten!
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module BorderColor
|
4
|
+
extend Parser::Base
|
5
|
+
|
6
|
+
class Parser < Parslet::Parser
|
7
|
+
include Color
|
8
|
+
|
9
|
+
rule(:border_color_side) {
|
10
|
+
color | symbol("transparent")
|
11
|
+
}
|
12
|
+
|
13
|
+
rule(:border_color) {
|
14
|
+
(
|
15
|
+
symbol("inherit") >> eof | (
|
16
|
+
border_color_side.maybe.as(:top) >>
|
17
|
+
border_color_side.maybe.as(:right) >>
|
18
|
+
border_color_side.maybe.as(:bottom) >>
|
19
|
+
border_color_side.maybe.as(:left)
|
20
|
+
)
|
21
|
+
).as(:border_color)
|
22
|
+
}
|
23
|
+
|
24
|
+
root(:border_color)
|
25
|
+
end
|
26
|
+
|
27
|
+
class Transformer < Parslet::Transform
|
28
|
+
@property = :border_color
|
29
|
+
extend MultiSideTransformer
|
30
|
+
extend Color::Transformer
|
31
|
+
extend Color::PlainColorValue
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def side_declaration(side, value)
|
35
|
+
Declaration.from_parser("border-#{side}-color", value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module BorderSide
|
4
|
+
class << self
|
5
|
+
def parse(property, inputs)
|
6
|
+
input = Array(inputs).join(" ")
|
7
|
+
side = find_side(property)
|
8
|
+
|
9
|
+
if parsed = self::Parser.new(side).try_parse(input)
|
10
|
+
self::Transformer.new.apply(parsed)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def find_side(property)
|
15
|
+
case property
|
16
|
+
when "border-top" then :top
|
17
|
+
when "border-right" then :right
|
18
|
+
when "border-bottom" then :bottom
|
19
|
+
when "border-left" then :left
|
20
|
+
else raise "Unknown property #{property}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Parser < Parslet::Parser
|
26
|
+
include Common
|
27
|
+
|
28
|
+
attr_reader :side
|
29
|
+
def initialize(side)
|
30
|
+
@side = side.to_sym
|
31
|
+
end
|
32
|
+
|
33
|
+
rule(:border_width) { BorderWidth::Parser.new.border_width_side }
|
34
|
+
rule(:border_style) { BorderStyle::Parser.new.border_style_side }
|
35
|
+
rule(:border_color) { BorderColor::Parser.new.border_color_side }
|
36
|
+
|
37
|
+
rule(:border_side_anonymous) {
|
38
|
+
border_width.maybe.as(:width) >>
|
39
|
+
border_style.maybe.as(:style) >>
|
40
|
+
border_color.maybe.as(:color)
|
41
|
+
}
|
42
|
+
|
43
|
+
rule(:border_side) {
|
44
|
+
(
|
45
|
+
symbol("inherit") >> eof |
|
46
|
+
border_side_anonymous.as(side)
|
47
|
+
).as(:border_side)
|
48
|
+
}
|
49
|
+
|
50
|
+
root(:border_side)
|
51
|
+
end
|
52
|
+
|
53
|
+
class Transformer < Parslet::Transform
|
54
|
+
extend Color::Transformer
|
55
|
+
extend Color::PlainColorValue
|
56
|
+
|
57
|
+
module Helpers
|
58
|
+
def transform_top(context); transform_side("top", context); end
|
59
|
+
def transform_right(context); transform_side("right", context); end
|
60
|
+
def transform_bottom(context); transform_side("bottom", context); end
|
61
|
+
def transform_left(context); transform_side("left", context); end
|
62
|
+
|
63
|
+
def transform_side(side, context)
|
64
|
+
width = context[:width]
|
65
|
+
style = context[:style]
|
66
|
+
color = context[:color]
|
67
|
+
|
68
|
+
[].tap do |declarations|
|
69
|
+
declarations << Declaration.from_parser("border-#{side}-width", width) if width
|
70
|
+
declarations << Declaration.from_parser("border-#{side}-style", style) if style
|
71
|
+
declarations << Declaration.from_parser("border-#{side}-color", color) if color
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
extend Helpers
|
76
|
+
|
77
|
+
rule(border_side: simple(:inherit)) {[]}
|
78
|
+
|
79
|
+
[:top, :right, :bottom, :left].each do |side|
|
80
|
+
rule(border_side: {
|
81
|
+
side => {
|
82
|
+
width:simple(:width),
|
83
|
+
style:simple(:style),
|
84
|
+
color:simple(:color)
|
85
|
+
}
|
86
|
+
}, &method("transform_#{side}"))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module BorderStyle
|
4
|
+
extend Parser::Base
|
5
|
+
|
6
|
+
class Parser < Parslet::Parser
|
7
|
+
include Common
|
8
|
+
|
9
|
+
rule(:border_style_side) {
|
10
|
+
symbol_list(%w(none hidden dotted dashed solid
|
11
|
+
double groove ridge inset outset
|
12
|
+
))
|
13
|
+
}
|
14
|
+
|
15
|
+
rule(:border_style) {
|
16
|
+
(
|
17
|
+
symbol("inherit") >> eof | (
|
18
|
+
border_style_side.maybe.as(:top) >>
|
19
|
+
border_style_side.maybe.as(:right) >>
|
20
|
+
border_style_side.maybe.as(:bottom) >>
|
21
|
+
border_style_side.maybe.as(:left)
|
22
|
+
)
|
23
|
+
).as(:border_style)
|
24
|
+
}
|
25
|
+
|
26
|
+
root(:border_style)
|
27
|
+
end
|
28
|
+
|
29
|
+
class Transformer < Parslet::Transform
|
30
|
+
@property = :border_style
|
31
|
+
extend MultiSideTransformer
|
32
|
+
|
33
|
+
class << self
|
34
|
+
def side_declaration(side, value)
|
35
|
+
Declaration.from_parser("border-#{side}-style", value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module BorderWidth
|
4
|
+
extend Parser::Base
|
5
|
+
|
6
|
+
class Parser < Parslet::Parser
|
7
|
+
include Common
|
8
|
+
|
9
|
+
rule(:border_width_side) {
|
10
|
+
symbol_list(%w(thin medium thick inherit)) | length
|
11
|
+
}
|
12
|
+
|
13
|
+
rule(:border_width) {
|
14
|
+
(
|
15
|
+
symbol("inherit") >> eof | (
|
16
|
+
border_width_side.maybe.as(:top) >>
|
17
|
+
border_width_side.maybe.as(:right) >>
|
18
|
+
border_width_side.maybe.as(:bottom) >>
|
19
|
+
border_width_side.maybe.as(:left)
|
20
|
+
)
|
21
|
+
).as(:border_width)
|
22
|
+
}
|
23
|
+
|
24
|
+
root(:border_width)
|
25
|
+
end
|
26
|
+
|
27
|
+
class Transformer < Parslet::Transform
|
28
|
+
@property = :border_width
|
29
|
+
extend MultiSideTransformer
|
30
|
+
|
31
|
+
def self.side_declaration(side, value)
|
32
|
+
Declaration.from_parser("border-#{side}-width", value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module Color
|
4
|
+
include Parslet
|
5
|
+
include Common
|
6
|
+
|
7
|
+
rule(:color) { (hexcolor | rgb | color_keyword).as(:color) }
|
8
|
+
rule(:rgb) { (rgb_with(numbers) | rgb_with(percent)).as(:rgb) }
|
9
|
+
rule(:hexcolor) { (str("#") >> match["a-fA-F0-9"].repeat(1)).as(:hexcolor) >> space? }
|
10
|
+
rule(:color_keyword) {
|
11
|
+
colors = %w(inherit black silver gray white maroon
|
12
|
+
red purple fuchsia green lime olive
|
13
|
+
yellow navy blue teal aqua)
|
14
|
+
colors.map {|c| symbol(c) }.reduce(:|).as(:keyword)
|
15
|
+
}
|
16
|
+
|
17
|
+
private
|
18
|
+
def rgb_with(parser)
|
19
|
+
symbol("rgb") >> parens do
|
20
|
+
parser >> space? >>
|
21
|
+
symbol(",") >>
|
22
|
+
parser >> space? >>
|
23
|
+
symbol(",") >>
|
24
|
+
parser >> space?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module Transformer
|
29
|
+
def self.extended(base)
|
30
|
+
base.instance_eval do
|
31
|
+
extend ClassMethods
|
32
|
+
|
33
|
+
rule(color:{rgb:simple(:value)}) {|c| transform_color(c)}
|
34
|
+
rule(color:{keyword:simple(:value)}) {|c| transform_color(c)}
|
35
|
+
rule(color:{hexcolor:simple(:value)}) {|c| transform_color(c)}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module ClassMethods
|
40
|
+
def transform_color(context)
|
41
|
+
Declaration.from_parser(@property.to_s.gsub("_", "-"), context[:value])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module PlainColorValue
|
47
|
+
def transform_color(context)
|
48
|
+
context[:value]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Csscss
|
2
|
+
module Parser
|
3
|
+
module Common
|
4
|
+
include Parslet
|
5
|
+
|
6
|
+
UNITS = %w(px em ex in cm mm pt pc)
|
7
|
+
|
8
|
+
rule(:space) { match['\s'].repeat(1) }
|
9
|
+
rule(:space?) { space.maybe }
|
10
|
+
rule(:number) { match["0-9"] }
|
11
|
+
rule(:numbers) { number.repeat(1) }
|
12
|
+
rule(:decimal) { numbers >> str(".").maybe >> numbers.maybe }
|
13
|
+
rule(:percent) { decimal >> stri("%") >> space? }
|
14
|
+
rule(:length) { decimal >> stri_list(UNITS) >> space? }
|
15
|
+
rule(:identifier) { match["a-zA-Z"].repeat(1) }
|
16
|
+
rule(:inherit) { stri("inherit") }
|
17
|
+
rule(:eof) { any.absent? }
|
18
|
+
rule(:nada) { any.repeat.as(:nada) }
|
19
|
+
|
20
|
+
rule(:http) {
|
21
|
+
(match['a-zA-Z.:/'] | str('\(') | str('\)')).repeat >> space?
|
22
|
+
}
|
23
|
+
|
24
|
+
rule(:url) {
|
25
|
+
stri("url") >> parens do
|
26
|
+
(any_quoted { http } >> space?) |
|
27
|
+
http
|
28
|
+
end
|
29
|
+
}
|
30
|
+
|
31
|
+
def stri(str)
|
32
|
+
key_chars = str.split(//)
|
33
|
+
key_chars.
|
34
|
+
collect! { |char|
|
35
|
+
if char.upcase == char.downcase
|
36
|
+
str(char)
|
37
|
+
else
|
38
|
+
match["#{char.upcase}#{char.downcase}"]
|
39
|
+
end
|
40
|
+
}.reduce(:>>)
|
41
|
+
end
|
42
|
+
|
43
|
+
def symbol(s, label = nil)
|
44
|
+
if label
|
45
|
+
stri(s).as(label) >> space?
|
46
|
+
else
|
47
|
+
stri(s) >> space?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def between(left, right)
|
52
|
+
raise "block not given" unless block_given?
|
53
|
+
symbol(left) >> yield >> symbol(right)
|
54
|
+
end
|
55
|
+
|
56
|
+
def parens(&block)
|
57
|
+
between("(", ")", &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def double_quoted(&block)
|
61
|
+
between('"', '"', &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def single_quoted(&block)
|
65
|
+
between("'", "'", &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
def any_quoted(&block)
|
69
|
+
double_quoted(&block) | single_quoted(&block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def stri_list(list)
|
73
|
+
list.map {|u| stri(u) }.reduce(:|)
|
74
|
+
end
|
75
|
+
|
76
|
+
def symbol_list(list)
|
77
|
+
list.map {|u| symbol(u) }.reduce(:|)
|
78
|
+
end
|
79
|
+
|
80
|
+
def try_parse(input)
|
81
|
+
parsed = (root | nada).parse(input)
|
82
|
+
parsed[:nada] ? false : parsed
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|