csscss 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/zmoazeni/csscss.png?branch=master)](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
|