deadfire 0.2.0 → 0.4.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/.github/workflows/ci.yml +2 -2
- data/Gemfile.lock +1 -1
- data/README.md +55 -32
- data/benchmarks/basic_benchmark.rb +47 -12
- data/benchmarks/tailwind_parser.rb +23 -0
- data/bin/console +16 -3
- data/changelog.md +38 -1
- data/lib/deadfire/ast_printer.rb +58 -0
- data/lib/deadfire/configuration.rb +18 -5
- data/lib/deadfire/css_generator.rb +65 -0
- data/lib/deadfire/error_reporter.rb +30 -0
- data/lib/deadfire/errors.rb +1 -14
- data/lib/deadfire/filename_helper.rb +49 -0
- data/lib/deadfire/front_end/apply_node.rb +43 -0
- data/lib/deadfire/front_end/at_rule_node.rb +19 -0
- data/lib/deadfire/front_end/base_node.rb +11 -0
- data/lib/deadfire/front_end/block_node.rb +21 -0
- data/lib/deadfire/front_end/comment_node.rb +17 -0
- data/lib/deadfire/front_end/newline_node.rb +17 -0
- data/lib/deadfire/front_end/parser.rb +156 -0
- data/lib/deadfire/front_end/ruleset_node.rb +18 -0
- data/lib/deadfire/front_end/scanner.rb +280 -0
- data/lib/deadfire/front_end/selector_node.rb +52 -0
- data/lib/deadfire/front_end/stylesheet_node.rb +21 -0
- data/lib/deadfire/front_end/token.rb +20 -0
- data/lib/deadfire/interpreter.rb +84 -0
- data/lib/deadfire/parser_engine.rb +41 -0
- data/lib/deadfire/spec.rb +135 -0
- data/lib/deadfire/version.rb +1 -1
- data/lib/deadfire.rb +34 -7
- metadata +23 -6
- data/lib/deadfire/css_buffer.rb +0 -37
- data/lib/deadfire/parser.rb +0 -387
- data/lib/deadfire/transformers/transformer.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82f838eee7d8e2ef83b302d7de509c428af8584567892296fd3011df42cb0990
|
4
|
+
data.tar.gz: 1a4b828032eda5dae38d3da5f820081402f7e66f919b2720ff8f9be65d6d8bf0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a724bdb7b939e5b4404ee5cee4266ad6c278ac5d4e7fc74f560884f4b30fc123c3492a52abd5028adbc9f579dd690beb26d0de2460e8cb3b8e482d44ce77e733
|
7
|
+
data.tar.gz: e353841bfb20e25ff0ff1556d555443546783a744cf96b2a2149862cf8dbebb31bb9c48f50d68f20355ea036c36e22ca4ac9f059413df500974f4888849673bd
|
data/.github/workflows/ci.yml
CHANGED
@@ -6,7 +6,7 @@ jobs:
|
|
6
6
|
strategy:
|
7
7
|
fail-fast: false
|
8
8
|
matrix:
|
9
|
-
ruby: [head, 3.1, 3.0, 2.7]
|
9
|
+
ruby: [head, 3.3, 3.2, 3.1, 3.0, 2.7]
|
10
10
|
steps:
|
11
11
|
- uses: actions/checkout@v3
|
12
12
|
- name: Set up Ruby
|
@@ -15,4 +15,4 @@ jobs:
|
|
15
15
|
ruby-version: ${{ matrix.ruby }}
|
16
16
|
bundler-cache: true
|
17
17
|
- name: Run tests
|
18
|
-
run: bundle exec rake
|
18
|
+
run: bundle exec rake
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
A lightweight CSS preprocessor.
|
4
4
|
|
5
|
-
Use plain ol' CSS with a little bit of @import
|
5
|
+
Use plain ol' CSS with a little bit of @import and @apply.
|
6
6
|
|
7
7
|
CSS is a staple technology when building web applications. With the introduction of LESS, SASS, SCSS it made CSS easier to maintain. However, most of these tools are no longer supported, maintained or have far too many features (wait... that's a bad thing?).
|
8
8
|
|
@@ -14,7 +14,6 @@ Deadfire can be used with or without a CSS framework.
|
|
14
14
|
|
15
15
|
- [x] @import
|
16
16
|
- [x] [@apply](https://tabatkins.github.io/specs/css-apply-rule/)
|
17
|
-
- [x] [nesting](https://drafts.csswg.org/css-nesting-1)
|
18
17
|
|
19
18
|
### @import
|
20
19
|
|
@@ -51,59 +50,65 @@ Output;
|
|
51
50
|
|
52
51
|
### @apply
|
53
52
|
|
54
|
-
|
53
|
+
The `@apply` directive inlines your classes into your custom CSS, simplifying the process of applying existing styles to a new class.
|
55
54
|
|
56
55
|
The CSS apply rule was [proposed to be included into CSS](https://tabatkins.github.io/specs/css-apply-rule/) however it was abandoned. Mixins simplify applying existing css to a new class.
|
57
56
|
|
58
|
-
|
59
|
-
|
60
|
-
Let's see an example of how to declare mixins and use the @apply directive.
|
57
|
+
Let's take a look at an example of how to use the @apply directive. Note that all utility classes are automatically cached.
|
61
58
|
|
62
59
|
```CSS
|
63
|
-
:
|
64
|
-
|
65
|
-
|
66
|
-
}
|
60
|
+
.font-bold: {
|
61
|
+
font-weight: bold;
|
62
|
+
}
|
67
63
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
}
|
64
|
+
.btn: {
|
65
|
+
padding-bottom: 10px;
|
66
|
+
text-align: center;
|
72
67
|
}
|
73
68
|
```
|
74
69
|
|
75
|
-
|
70
|
+
Re-use the styles using @apply:
|
76
71
|
|
77
72
|
```CSS
|
78
73
|
.btn-blue {
|
79
|
-
@apply
|
74
|
+
@apply .btn .font-bold;
|
80
75
|
}
|
81
76
|
|
82
77
|
.homepage-hero {
|
83
|
-
@apply
|
78
|
+
@apply .font-bold;
|
84
79
|
}
|
85
80
|
```
|
86
81
|
|
87
|
-
###
|
82
|
+
### Nesting
|
88
83
|
|
89
|
-
Nesting
|
84
|
+
The CSS nesting feature, as described in the CSS Nesting specification (https://drafts.csswg.org/css-nesting/), allows for more intuitive and concise styling by enabling the nesting of CSS rules within one another. This feature simplifies the structure of stylesheets and improves readability.
|
90
85
|
|
91
|
-
|
86
|
+
Now that nesting has been upstreamed to CSS, meaning it is now a part of the official CSS specification. As a result, Deafire will leverage the native CSS nesting feature instead of implementing this feature (which was the original goal of this project).
|
92
87
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
88
|
+
Example:
|
89
|
+
|
90
|
+
```css
|
91
|
+
.foo {
|
92
|
+
color: green;
|
93
|
+
}
|
94
|
+
.foo .bar {
|
95
|
+
font-size: 1.4rem;
|
96
|
+
}
|
97
|
+
|
98
|
+
/* can be simplified to */
|
99
|
+
.foo {
|
100
|
+
color: green;
|
101
|
+
.bar {
|
102
|
+
font-size: 1.4rem;
|
103
|
+
}
|
98
104
|
}
|
99
105
|
```
|
100
106
|
|
101
|
-
|
107
|
+
### Fault tolerant
|
102
108
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
```
|
109
|
+
When Deadfire encounters an error, such as a missing mixin or other issues, it does not immediately raise an error that would halt the execution. Instead, it continues processing the CSS code and collects the encountered errors. These errors are then reported through the ErrorReporter class, allowing you to handle or display them as needed.
|
110
|
+
|
111
|
+
By adopting this fault-tolerant approach, Deadfire aims to provide more flexibility and resilience when dealing with CSS code that may contain errors or inconsistencies. It allows you to gather information about the encountered issues and take appropriate actions based on the reported errors.
|
107
112
|
|
108
113
|
## Installation
|
109
114
|
|
@@ -123,7 +128,25 @@ Or install it yourself as:
|
|
123
128
|
|
124
129
|
## Deadfire + Ruby on Rails
|
125
130
|
|
126
|
-
After adding Deadfire gem to your rails application, open the file `config/initializers/assets.rb`
|
131
|
+
After adding Deadfire gem to your rails application, open the file `config/initializers/assets.rb` or create a new initializer `config/initializers/deadfire.rb`.
|
132
|
+
|
133
|
+
### Propshaft
|
134
|
+
|
135
|
+
To setup Propshaft to use Deadfire as a preprocessor:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
# config/initializers/assets.rb
|
139
|
+
class DeadfireCompiler < Propshaft::Compiler
|
140
|
+
def compile(logical_path, input)
|
141
|
+
Deadfire.parse(input, root_path: Rails.root.join("app", "assets", "stylesheets"))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
Rails.application.config.assets.compilers << ["text/css", DeadfireCompiler]
|
146
|
+
```
|
147
|
+
### Sprockets
|
148
|
+
|
149
|
+
To setup Sprocket to use Deadfire as a preprocessor:
|
127
150
|
|
128
151
|
```ruby
|
129
152
|
# config/initializers/assets.rb
|
@@ -156,4 +179,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
156
179
|
|
157
180
|
## Code of Conduct
|
158
181
|
|
159
|
-
Everyone interacting in the Deadfire project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hahmed/deadfire/blob/master/CODE_OF_CONDUCT.md).
|
182
|
+
Everyone interacting in the Deadfire project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hahmed/deadfire/blob/master/CODE_OF_CONDUCT.md).
|
@@ -8,12 +8,13 @@ gemfile(true) do
|
|
8
8
|
gem "sassc"
|
9
9
|
gem "deadfire", github: "hahmed/deadfire", branch: "main"
|
10
10
|
gem "syntax_tree-css"
|
11
|
+
gem "sass-embedded"
|
11
12
|
|
12
13
|
gem "benchmark-ips"
|
13
14
|
end
|
14
15
|
|
15
16
|
css = <<~CSS
|
16
|
-
|
17
|
+
/* My very first css file! */
|
17
18
|
body {
|
18
19
|
font-family: helvetica, arial, sans-serif;
|
19
20
|
font-size: calc(1.3em + 0.5vw);
|
@@ -25,9 +26,12 @@ body {
|
|
25
26
|
}
|
26
27
|
|
27
28
|
h1 {
|
28
|
-
font-size: 40px;
|
29
|
+
font-size: 40px;
|
29
30
|
}
|
30
|
-
|
31
|
+
/* Just
|
32
|
+
a
|
33
|
+
random
|
34
|
+
comment */
|
31
35
|
a {
|
32
36
|
font-size: 1em;
|
33
37
|
vertical-align: baseline;
|
@@ -41,9 +45,7 @@ a {
|
|
41
45
|
text-decoration-width: 0.1rem
|
42
46
|
}
|
43
47
|
|
44
|
-
.button--block {
|
45
|
-
min-width:100% !important
|
46
|
-
}
|
48
|
+
.button--block { min-width:100% !important }
|
47
49
|
|
48
50
|
code {
|
49
51
|
font-family: Roboto Mono;
|
@@ -51,26 +53,59 @@ code {
|
|
51
53
|
color: gray;
|
52
54
|
}
|
53
55
|
|
56
|
+
/* I like code blocks!!!!!======= */
|
57
|
+
|
54
58
|
.banner {
|
55
59
|
border: 1px solid #ccc;
|
56
60
|
}
|
57
61
|
CSS
|
58
62
|
|
59
|
-
def dartsass
|
60
|
-
system "sass benchmarks/input.scss output.css", exception: true
|
61
|
-
end
|
62
|
-
|
63
63
|
Benchmark.ips do |x|
|
64
64
|
x.config(:time => 5, :warmup => 2)
|
65
65
|
|
66
|
-
x.report("dartsass") { dartsass }
|
66
|
+
# x.report("dartsass") { dartsass }
|
67
67
|
x.report("deadfire") { Deadfire.parse(css) }
|
68
68
|
x.report("sassc") { SassC::Engine.new(css).render }
|
69
69
|
x.report("sytanx_tree") { SyntaxTree::CSS.parse(css) }
|
70
|
+
x.report("dart sass") { Sass.compile_string(css) }
|
70
71
|
x.compare!
|
71
72
|
end
|
72
73
|
|
73
|
-
#
|
74
|
+
# May 2024: Re-added dart sass
|
75
|
+
# Warming up --------------------------------------
|
76
|
+
# deadfire 172.000 i/100ms
|
77
|
+
# sassc 85.000 i/100ms
|
78
|
+
# sytanx_tree 79.000 i/100ms
|
79
|
+
# dart sass 520.000 i/100ms
|
80
|
+
# Calculating -------------------------------------
|
81
|
+
# deadfire 1.680k (± 0.9%) i/s - 8.428k in 5.018094s
|
82
|
+
# sassc 816.292 (± 0.2%) i/s - 4.165k in 5.102378s
|
83
|
+
# sytanx_tree 750.421 (± 1.9%) i/s - 3.792k in 5.054908s
|
84
|
+
# dart sass 5.225k (± 4.7%) i/s - 26.520k in 5.090927s
|
85
|
+
|
86
|
+
# Comparison:
|
87
|
+
# dart sass: 5224.7 i/s
|
88
|
+
# deadfire: 1679.7 i/s - 3.11x slower
|
89
|
+
# sassc: 816.3 i/s - 6.40x slower
|
90
|
+
# sytanx_tree: 750.4 i/s - 6.96x slower
|
91
|
+
|
92
|
+
# Nov 2023: (Note: removed dart sass because I don't have it installed, need to re-run again)
|
93
|
+
# Warming up --------------------------------------
|
94
|
+
# deadfire 116.000 i/100ms
|
95
|
+
# sassc 69.000 i/100ms
|
96
|
+
# sytanx_tree 64.000 i/100ms
|
97
|
+
# Calculating -------------------------------------
|
98
|
+
# deadfire 1.164k (± 1.2%) i/s - 5.916k in 5.084777s
|
99
|
+
# sassc 695.721 (± 1.3%) i/s - 3.519k in 5.059025s
|
100
|
+
# sytanx_tree 635.684 (± 3.3%) i/s - 3.200k in 5.040489s
|
101
|
+
|
102
|
+
# Comparison:
|
103
|
+
# deadfire: 1163.6 i/s
|
104
|
+
# sassc: 695.7 i/s - 1.67x slower
|
105
|
+
# sytanx_tree: 635.7 i/s - 1.83x slower
|
106
|
+
|
107
|
+
|
108
|
+
# Sep 2022:
|
74
109
|
# Warming up --------------------------------------
|
75
110
|
# dartsass 1.000 i/100ms
|
76
111
|
# deadfire 1.088k i/100ms
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bundler/inline"
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
gemfile(true) do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
|
7
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
8
|
+
|
9
|
+
gem "deadfire", path: "./" #github: "hahmed/deadfire", branch: "main"
|
10
|
+
end
|
11
|
+
|
12
|
+
css = File.read("./benchmarks/tailwind.css")
|
13
|
+
|
14
|
+
puts css.inspect
|
15
|
+
puts "---"
|
16
|
+
|
17
|
+
|
18
|
+
time = Benchmark.measure do
|
19
|
+
parser = Deadfire::ParserEngine.new(css)
|
20
|
+
parser.parse
|
21
|
+
end
|
22
|
+
|
23
|
+
puts time.real
|
data/bin/console
CHANGED
@@ -6,9 +6,22 @@ require "deadfire"
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
|
-
#
|
10
|
-
|
11
|
-
|
9
|
+
# simple css test
|
10
|
+
css = <<-CSS
|
11
|
+
@page :first { margin: 1cm; }
|
12
|
+
CSS
|
13
|
+
|
14
|
+
# @charset "UTF-8";
|
15
|
+
# @viewport { width: device-width; }
|
16
|
+
# @font-face {
|
17
|
+
# font-family: "Open Sans";
|
18
|
+
# }
|
19
|
+
|
20
|
+
puts css.inspect
|
21
|
+
|
22
|
+
parser = Deadfire::ParserEngine.new(css)
|
23
|
+
parser.print_ast
|
24
|
+
puts parser.parse
|
12
25
|
|
13
26
|
require "irb"
|
14
27
|
IRB.start(__FILE__)
|
data/changelog.md
CHANGED
@@ -1,5 +1,42 @@
|
|
1
1
|
## Changelog
|
2
|
+
### 0.5.0 (current)
|
3
|
+
|
4
|
+
### 0.4.0 (18 May 2024)
|
5
|
+
- Fix parsing comments that have 2 stars e.g. /**
|
6
|
+
- Adds a logger and a default setting that suppresses the logs which can be configured to report errors.
|
7
|
+
- Fixes issue with import's not parsing correctly when there is no ending semicolon.
|
8
|
+
- Added ci for ruby 3.3
|
9
|
+
- Add support for importing .scss files, making it easier to migrate from other libraries.
|
10
|
+
```
|
11
|
+
@import "nav"
|
12
|
+
@import "sidebar.scss"
|
13
|
+
.image { padding: 2px; }
|
14
|
+
```
|
15
|
+
Deadfire will look for the file nav.css, then nav.scss in the `config.root_path` in the case when a file extension is not included.
|
16
|
+
|
17
|
+
- Simplify the configuration by having one option called compressed instead of keep_newlines and keep_comments.
|
18
|
+
|
19
|
+
### 0.3.0 (15 November 2023)
|
20
|
+
|
21
|
+
- Redo the parser by splitting up the tokenizer, parser, interpreter and generator phases which makes each step simpler. It's still faster than sassc but much slower than it was previously which is something I hope to address soon.
|
22
|
+
- Key thing to note is that Deadfire now only handles @imports and mixins. Nesting is now a feature of CSS, which means Deadfire is much simpler as a result.
|
23
|
+
- In the next version I will drop the old parser and it's tests.
|
24
|
+
- Add support for Ruby 3.2
|
25
|
+
- Updated docs and added an example on how to get Deadfire working with Propshaft.
|
26
|
+
|
27
|
+
### 0.2.0 (25 October 2022)
|
28
|
+
|
29
|
+
- Added build for ruby 3.0
|
30
|
+
- StringIO is now hidden and only visible on the buffer class.
|
31
|
+
- Fixed a bug with a css ruleset after a nested block was being ignored, example;
|
32
|
+
```
|
33
|
+
.title {
|
34
|
+
color: blue;
|
35
|
+
& .text { padding: 3px; }
|
36
|
+
}
|
37
|
+
.image { padding: 2px; }
|
38
|
+
```
|
2
39
|
|
3
40
|
### 0.1.0 (17 October 2022)
|
4
41
|
|
5
|
-
Initial release
|
42
|
+
Initial release
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deadfire
|
4
|
+
class AstPrinter # :nodoc:
|
5
|
+
def initialize
|
6
|
+
@indentation = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def print(node)
|
10
|
+
node.accept(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def visit_stylesheet_node(node)
|
14
|
+
puts "StylesheetNode"
|
15
|
+
node.statements.each do |statement|
|
16
|
+
# something
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_at_rule_node(node)
|
21
|
+
puts "AtRuleNode"
|
22
|
+
puts " AtKeyword: #{node.at_keyword.lexeme}"
|
23
|
+
node.value.each do |value|
|
24
|
+
puts " Value: #{value}"
|
25
|
+
end
|
26
|
+
if node.block
|
27
|
+
visit_block_node(node.block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_block_node(node)
|
32
|
+
puts "BlockNode"
|
33
|
+
node.declarations.each do |declaration|
|
34
|
+
case declaration
|
35
|
+
when FrontEnd::Token
|
36
|
+
puts " Declaration: #{declaration.lexeme}"
|
37
|
+
when FrontEnd::AtRuleNode
|
38
|
+
visit_at_rule_node(declaration)
|
39
|
+
when FrontEnd::RulesetNode
|
40
|
+
visit_ruleset_node(declaration)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def visit_ruleset_node(node)
|
46
|
+
puts "RulesetNode"
|
47
|
+
puts " Selector: #{node.selector}"
|
48
|
+
if node.block
|
49
|
+
visit_block_node(node.block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def visit_comment_node(node)
|
54
|
+
puts "CommentNode"
|
55
|
+
puts " Comment: #{node.comment.lexeme}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,24 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "logger"
|
2
3
|
|
3
4
|
module Deadfire
|
4
5
|
class Configuration
|
5
|
-
attr_reader :directories, :root_path, :
|
6
|
+
attr_reader :directories, :root_path, :compressed, :logger, :supressed
|
6
7
|
|
7
8
|
def initialize
|
8
9
|
@directories = []
|
9
10
|
@root_path = ""
|
10
|
-
@
|
11
|
+
@compressed = false
|
12
|
+
@logger = Logger.new(STDOUT, level: :warn)
|
13
|
+
@supressed = true
|
11
14
|
end
|
12
15
|
|
13
16
|
def root_path=(value)
|
17
|
+
return if value.nil?
|
18
|
+
|
14
19
|
unless Dir.exist?(value)
|
15
20
|
raise DirectoryNotFoundError.new("Root not found #{value}")
|
16
21
|
end
|
17
22
|
@root_path = value
|
18
23
|
end
|
19
24
|
|
20
|
-
def
|
21
|
-
@
|
25
|
+
def compressed=(value)
|
26
|
+
@compressed = value unless value.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger=(value)
|
30
|
+
@logger = value
|
31
|
+
end
|
32
|
+
|
33
|
+
def supressed=(value)
|
34
|
+
@supressed = value
|
22
35
|
end
|
23
36
|
end
|
24
|
-
end
|
37
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Frozen_string_literal: true
|
2
|
+
require "stringio"
|
3
|
+
|
4
|
+
module Deadfire
|
5
|
+
class CssGenerator # :nodoc:
|
6
|
+
def initialize(tree)
|
7
|
+
@tree = tree
|
8
|
+
@output = StringIO.new # TODO: write to file instead of string buffer in temp folder
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
@tree.accept(self)
|
13
|
+
@output.string
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit_stylesheet_node(node)
|
17
|
+
node.statements.each { |child| child.accept(self) }.join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_at_rule_node(node)
|
21
|
+
@output << node.at_keyword.lexeme
|
22
|
+
node.value.each do |value|
|
23
|
+
@output << value.lexeme
|
24
|
+
end
|
25
|
+
|
26
|
+
if node.block
|
27
|
+
visit_block_node(node.block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_ruleset_node(node)
|
32
|
+
@output << node.selector.selector
|
33
|
+
@output << " "
|
34
|
+
|
35
|
+
visit_block_node(node.block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_block_node(node)
|
39
|
+
node.declarations.each do |declaration|
|
40
|
+
case declaration
|
41
|
+
when ApplyNode
|
42
|
+
visit_apply_node(declaration)
|
43
|
+
when FrontEnd::BlockNode
|
44
|
+
visit_block_node(declaration)
|
45
|
+
when FrontEnd::AtRuleNode
|
46
|
+
visit_at_rule_node(declaration)
|
47
|
+
else
|
48
|
+
@output << declaration.lexeme
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def visit_newline_node(node)
|
54
|
+
@output << node.text
|
55
|
+
end
|
56
|
+
|
57
|
+
def visit_apply_node(node)
|
58
|
+
@output << node.node.lexeme
|
59
|
+
end
|
60
|
+
|
61
|
+
def visit_comment_node(node)
|
62
|
+
@output << node.comment.lexeme unless Deadfire.configuration.compressed
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deadfire
|
4
|
+
class ErrorReporter # :nodoc:
|
5
|
+
attr_reader :errors
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@errors = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def error(line, message)
|
12
|
+
error = Error.new(line, message)
|
13
|
+
Deadfire.configuration.logger.error(error.to_s) unless Deadfire.configuration.supressed
|
14
|
+
@errors << error
|
15
|
+
end
|
16
|
+
|
17
|
+
def errors?
|
18
|
+
@errors.any?
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# create error struct with line and message
|
24
|
+
Error = Struct.new(:line, :message) do
|
25
|
+
def to_s
|
26
|
+
"Line #{line}: #{message}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/deadfire/errors.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
module Deadfire
|
4
4
|
class DirectoryNotFoundError < StandardError; end
|
5
|
-
class Error < StandardError; end
|
6
5
|
|
7
6
|
class DuplicateImportException < StandardError
|
8
7
|
def initialize(filename = "", lineno = "")
|
@@ -27,16 +26,4 @@ module Deadfire
|
|
27
26
|
super(msg)
|
28
27
|
end
|
29
28
|
end
|
30
|
-
|
31
|
-
class EarlyApplyException < StandardError
|
32
|
-
def initialize(input = "", lineno = "")
|
33
|
-
msg = if input
|
34
|
-
"Error with input: `#{input}` line: #{lineno}"
|
35
|
-
else
|
36
|
-
"Apply called too early in css. There are no mixins defined."
|
37
|
-
end
|
38
|
-
|
39
|
-
super(msg)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deadfire
|
4
|
+
class FilenameHelper
|
5
|
+
class << self
|
6
|
+
def resolve_import_path(line, lineno = 0)
|
7
|
+
path = normalize_path(line)
|
8
|
+
potential = potential_path(path)
|
9
|
+
ext = File.extname(path)
|
10
|
+
|
11
|
+
if ext && valid_file?(potential)
|
12
|
+
potential
|
13
|
+
else
|
14
|
+
possible_paths(path)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def normalize_path(line)
|
19
|
+
path = line.split.last
|
20
|
+
path.gsub!("\"", "")
|
21
|
+
path.gsub!("\'", "")
|
22
|
+
path.gsub!(";", "")
|
23
|
+
path
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def valid_file_extension?(ext)
|
29
|
+
Deadfire::PERMISSIBLE_FILE_EXTENSIONS.include?(ext)
|
30
|
+
end
|
31
|
+
|
32
|
+
def valid_file?(path)
|
33
|
+
File.exist?(path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def possible_paths(path)
|
37
|
+
Deadfire::PERMISSIBLE_FILE_EXTENSIONS.each do |ext|
|
38
|
+
option = File.join(Deadfire.configuration.root_path, path + ext)
|
39
|
+
return option if valid_file?(option)
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def potential_path(path)
|
45
|
+
File.join(Deadfire.configuration.root_path, path)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|