roadie 3.5.1 → 5.0.1
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/main.yml +43 -0
- data/.rubocop.yml +5 -0
- data/.solargraph.yml +16 -0
- data/Changelog.md +30 -4
- data/Gemfile +7 -2
- data/README.md +12 -14
- data/Rakefile +4 -3
- data/lib/roadie/asset_provider.rb +5 -1
- data/lib/roadie/asset_scanner.rb +8 -6
- data/lib/roadie/cached_provider.rb +3 -0
- data/lib/roadie/deduplicator.rb +3 -0
- data/lib/roadie/document.rb +10 -11
- data/lib/roadie/errors.rb +22 -16
- data/lib/roadie/filesystem_provider.rb +15 -3
- data/lib/roadie/inliner.rb +51 -19
- data/lib/roadie/markup_improver.rb +24 -31
- data/lib/roadie/net_http_provider.rb +27 -12
- data/lib/roadie/null_provider.rb +20 -5
- data/lib/roadie/null_url_rewriter.rb +11 -3
- data/lib/roadie/path_rewriter_provider.rb +6 -1
- data/lib/roadie/provider_list.rb +17 -11
- data/lib/roadie/rspec/asset_provider.rb +6 -1
- data/lib/roadie/rspec/cache_store.rb +2 -0
- data/lib/roadie/rspec.rb +4 -2
- data/lib/roadie/selector.rb +18 -5
- data/lib/roadie/style_attribute_builder.rb +4 -1
- data/lib/roadie/style_block.rb +5 -3
- data/lib/roadie/style_property.rb +5 -2
- data/lib/roadie/stylesheet.rb +4 -13
- data/lib/roadie/url_generator.rb +26 -8
- data/lib/roadie/url_rewriter.rb +12 -9
- data/lib/roadie/utils.rb +3 -1
- data/lib/roadie/version.rb +1 -1
- data/lib/roadie.rb +25 -23
- data/roadie.gemspec +23 -23
- data/spec/hash_as_cache_store_spec.rb +3 -1
- data/spec/integration_spec.rb +43 -44
- data/spec/lib/roadie/asset_scanner_spec.rb +11 -5
- data/spec/lib/roadie/cached_provider_spec.rb +6 -4
- data/spec/lib/roadie/css_not_found_spec.rb +10 -5
- data/spec/lib/roadie/deduplicator_spec.rb +5 -3
- data/spec/lib/roadie/document_spec.rb +47 -28
- data/spec/lib/roadie/filesystem_provider_spec.rb +10 -11
- data/spec/lib/roadie/inliner_spec.rb +42 -45
- data/spec/lib/roadie/markup_improver_spec.rb +19 -26
- data/spec/lib/roadie/net_http_provider_spec.rb +16 -14
- data/spec/lib/roadie/null_provider_spec.rb +4 -3
- data/spec/lib/roadie/null_url_rewriter_spec.rb +4 -3
- data/spec/lib/roadie/path_rewriter_provider_spec.rb +6 -4
- data/spec/lib/roadie/provider_list_spec.rb +27 -22
- data/spec/lib/roadie/selector_spec.rb +7 -5
- data/spec/lib/roadie/style_attribute_builder_spec.rb +7 -5
- data/spec/lib/roadie/style_block_spec.rb +3 -2
- data/spec/lib/roadie/style_property_spec.rb +10 -8
- data/spec/lib/roadie/stylesheet_spec.rb +4 -21
- data/spec/lib/roadie/test_provider_spec.rb +6 -4
- data/spec/lib/roadie/url_generator_spec.rb +3 -2
- data/spec/lib/roadie/url_rewriter_spec.rb +10 -7
- data/spec/lib/roadie/utils_spec.rb +2 -0
- data/spec/shared_examples/asset_provider.rb +2 -0
- data/spec/shared_examples/url_rewriter.rb +5 -3
- data/spec/spec_helper.rb +10 -8
- data/spec/support/have_attribute_matcher.rb +3 -2
- data/spec/support/have_node_matcher.rb +5 -3
- data/spec/support/have_selector_matcher.rb +4 -3
- data/spec/support/have_styling_matcher.rb +12 -11
- data/spec/support/have_xpath_matcher.rb +4 -3
- data/spec/support/test_provider.rb +2 -0
- metadata +24 -8
- data/.travis.yml +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ac28a4d983148b5e8c799804e754b81d9d7a04b4ef97f97bcc6592d37a74bed
|
4
|
+
data.tar.gz: 9dbeb2fb1d41e301bf7d7c4049e476da22604bfc70047f6dc843ab6c1a489048
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5146cfb6152aad59b410670b792788bc84af5a9064c353628fae6cc1a1b2a2854703872990c47788c9369fef4469ee15b0040f192aeda1e32dcd8eef934e6327
|
7
|
+
data.tar.gz: 80418199d7ea29608e7997ee4ccfb591dbe8bd1eb3c609b59e8fc857b0d056103fcc9e74fafab6cd32f041ea8051870c41a5e6807b24d4c233e46803ab498750
|
@@ -0,0 +1,43 @@
|
|
1
|
+
name: Main
|
2
|
+
on:
|
3
|
+
push:
|
4
|
+
branches:
|
5
|
+
- main
|
6
|
+
- master
|
7
|
+
|
8
|
+
pull_request:
|
9
|
+
types: [opened, synchronize, reopened]
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
base:
|
13
|
+
name: Ruby ${{ matrix.ruby }}
|
14
|
+
runs-on: ubuntu-20.04
|
15
|
+
strategy:
|
16
|
+
fail-fast: false
|
17
|
+
matrix:
|
18
|
+
ruby: ["2.6", "2.7", "3.0", "3.1"]
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- name: Checkout code
|
22
|
+
uses: actions/checkout@v2
|
23
|
+
|
24
|
+
# This setup is not compatible with the way Travis CI was
|
25
|
+
# setup, so the cache will only work for the root folder.
|
26
|
+
- name: Setup Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: ${{ matrix.ruby }}
|
30
|
+
bundler-cache: true
|
31
|
+
|
32
|
+
- name: Rake
|
33
|
+
run: bundle exec rake
|
34
|
+
|
35
|
+
- uses: codecov/codecov-action@v2
|
36
|
+
|
37
|
+
lint:
|
38
|
+
runs-on: ubuntu-latest
|
39
|
+
steps:
|
40
|
+
- name: standardrb
|
41
|
+
env:
|
42
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
43
|
+
uses: amoeba/standardrb-action@v2
|
data/.rubocop.yml
ADDED
data/.solargraph.yml
ADDED
data/Changelog.md
CHANGED
@@ -1,10 +1,37 @@
|
|
1
1
|
### dev
|
2
2
|
|
3
|
-
|
3
|
+
[full changelog](https://github.com/Mange/roadie/compare/v5.0.1...master)
|
4
|
+
|
5
|
+
Nothing yet.
|
6
|
+
|
7
|
+
### 5.0.1
|
8
|
+
|
9
|
+
[full changelog](https://github.com/Mange/roadie/compare/v5.0.0...v5.0.1)
|
10
|
+
|
11
|
+
* Don't try to inline [the `:host`
|
12
|
+
pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/:host) -
|
13
|
+
[viamin (Bart Agapinan)](https://github.com/viamin). (#170)
|
4
14
|
|
5
|
-
|
15
|
+
### 5.0.0
|
6
16
|
|
7
|
-
|
17
|
+
[full changelog](https://github.com/Mange/roadie/compare/v4.0.0...v5.0.0)
|
18
|
+
|
19
|
+
* Drop support for Ruby 2.4 and Ruby 2.5
|
20
|
+
* Drop support for JRuby and Rubinius
|
21
|
+
* Test with Ruby 2.7 - [aried3r (Anton Rieder)](https://github.com/aried3r) (#167)
|
22
|
+
* Test with Ruby 3.0 and Ruby 3.1
|
23
|
+
* Add standardrb as code formatter
|
24
|
+
* Drop support for callbacks that accepts only a single argument.
|
25
|
+
* Change signature of `Roadie::CssNotFound` and `Roadie::ProvidersFailed`.
|
26
|
+
|
27
|
+
### 4.0.0
|
28
|
+
|
29
|
+
[full changelog](https://github.com/Mange/roadie/compare/v3.5.1...v4.0.0)
|
30
|
+
|
31
|
+
* Drop support for Ruby 2.1, 2.2, and 2.3 and
|
32
|
+
add support for frozen string literals and Ruby 2.6 - [adamkiczula (Adam
|
33
|
+
Kiczula)](https://github.com/adamkiczula) (#164)
|
34
|
+
* `Roadie::Stylesheet#each_inlinable_block` is now removed.
|
8
35
|
|
9
36
|
### 3.5.1
|
10
37
|
|
@@ -380,4 +407,3 @@ Roadie fork!
|
|
380
407
|
* + some other enhancements
|
381
408
|
* Deprecations:
|
382
409
|
* Removed support for Rails 2.x
|
383
|
-
|
data/Gemfile
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
2
4
|
gemspec
|
3
5
|
|
4
6
|
# Added here so it does not show up on the Gemspec; I only want it for CI builds
|
5
|
-
gem
|
7
|
+
gem "codecov", group: :test, require: false
|
8
|
+
# Not actually required to run the tests for the gem, but a real convenience
|
9
|
+
# for local development.
|
10
|
+
gem "standard", group: [:test, :development], require: false
|
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
Roadie
|
2
2
|
======
|
3
3
|
|
4
|
-
[](http://travis-ci.org/#!/Mange/roadie)
|
5
4
|
[](https://codeclimate.com/github/Mange/roadie)
|
6
5
|
[](https://codecov.io/github/Mange/roadie?branch=master)
|
7
6
|
[](https://rubygems.org/gems/roadie)
|
@@ -55,7 +54,7 @@ Install & Usage
|
|
55
54
|
[Add this gem to your Gemfile as recommended by Rubygems](http://rubygems.org/gems/roadie) and run `bundle install`.
|
56
55
|
|
57
56
|
```ruby
|
58
|
-
gem 'roadie', '~>
|
57
|
+
gem 'roadie', '~> 4.0'
|
59
58
|
```
|
60
59
|
|
61
60
|
You can then create a new instance of a Roadie document:
|
@@ -333,7 +332,10 @@ class UserAssetsProvider
|
|
333
332
|
end
|
334
333
|
|
335
334
|
def find_stylesheet!(name)
|
336
|
-
find_stylesheet(name) or
|
335
|
+
find_stylesheet(name) or
|
336
|
+
raise Roadie::CssNotFound.new(
|
337
|
+
css_name: name, message: "does not match a user stylesheet", provider: self
|
338
|
+
)
|
337
339
|
end
|
338
340
|
|
339
341
|
# Instead of implementing #find_stylesheet!, you could also:
|
@@ -444,18 +446,14 @@ Partial documents does not have a `<!DOCTYPE>`.
|
|
444
446
|
Build Status
|
445
447
|
------------
|
446
448
|
|
447
|
-
Tested with
|
449
|
+
Tested with Github CI using:
|
448
450
|
|
449
|
-
* MRI 2.
|
450
|
-
* MRI 2.
|
451
|
-
* MRI
|
452
|
-
* MRI
|
453
|
-
* JRuby (latest)
|
454
|
-
* Rubinius (failures on Rubinius will not fail the build due to a long history of instability in `rbx`)
|
451
|
+
* MRI 2.6
|
452
|
+
* MRI 2.7
|
453
|
+
* MRI 3.0
|
454
|
+
* MRI 3.1
|
455
455
|
|
456
|
-
|
457
|
-
|
458
|
-
Let me know if you want any other VM supported officially.
|
456
|
+
Let me know if you want any other runtime supported officially.
|
459
457
|
|
460
458
|
### Versioning ###
|
461
459
|
|
@@ -565,7 +563,7 @@ License
|
|
565
563
|
|
566
564
|
(The MIT License)
|
567
565
|
|
568
|
-
Copyright (c) 2009-
|
566
|
+
Copyright (c) 2009-2022 Magnus Bergmark, Jim Neath / Purify, and contributors.
|
569
567
|
|
570
568
|
* [Magnus Bergmark](https://github.com/Mange) <magnus.bergmark@gmail.com>
|
571
569
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/setup"
|
3
4
|
|
4
5
|
Bundler::GemHelper.install_tasks
|
5
6
|
|
@@ -9,4 +10,4 @@ task :spec do
|
|
9
10
|
end
|
10
11
|
|
11
12
|
desc "Default: Run specs"
|
12
|
-
task :
|
13
|
+
task default: :spec
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# This module can be included in your own code to help you implement the
|
3
5
|
# standard behavior for asset providers.
|
@@ -5,7 +7,9 @@ module Roadie
|
|
5
7
|
# It helps you by declaring {#find_stylesheet!} in the terms of #find_stylesheet in your own class.
|
6
8
|
module AssetProvider
|
7
9
|
def find_stylesheet!(name)
|
8
|
-
find_stylesheet(name) or raise
|
10
|
+
find_stylesheet(name) or raise(
|
11
|
+
CssNotFound.new(css_name: name, provider: self)
|
12
|
+
)
|
9
13
|
end
|
10
14
|
end
|
11
15
|
end
|
data/lib/roadie/asset_scanner.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# @api private
|
3
5
|
#
|
@@ -41,15 +43,15 @@ module Roadie
|
|
41
43
|
# @see #find_css
|
42
44
|
# @return [Enumerable<Stylesheet>] every extracted stylesheet
|
43
45
|
def extract_css
|
44
|
-
|
46
|
+
@dom.css(STYLE_ELEMENT_QUERY).map { |element|
|
45
47
|
stylesheet = read_stylesheet(element)
|
46
48
|
element.remove if stylesheet
|
47
49
|
stylesheet
|
48
50
|
}.compact
|
49
|
-
stylesheets
|
50
51
|
end
|
51
52
|
|
52
53
|
private
|
54
|
+
|
53
55
|
STYLE_ELEMENT_QUERY = (
|
54
56
|
"style:not([data-roadie-ignore]), " +
|
55
57
|
# TODO: When using Nokogiri 1.6.1 and later; we may use a double :not here
|
@@ -73,7 +75,7 @@ module Roadie
|
|
73
75
|
def read_stylesheet(element)
|
74
76
|
if element.name == "style"
|
75
77
|
read_style_element element
|
76
|
-
elsif element.name == "link" && element[
|
78
|
+
elsif element.name == "link" && element["media"] != "print" && element["href"]
|
77
79
|
read_link_element element
|
78
80
|
end
|
79
81
|
end
|
@@ -84,14 +86,14 @@ module Roadie
|
|
84
86
|
|
85
87
|
def read_link_element(element)
|
86
88
|
if Utils.path_is_absolute?(element["href"])
|
87
|
-
external_asset_provider.find_stylesheet! element[
|
89
|
+
external_asset_provider.find_stylesheet! element["href"] if should_find_external?
|
88
90
|
else
|
89
|
-
normal_asset_provider.find_stylesheet! element[
|
91
|
+
normal_asset_provider.find_stylesheet! element["href"]
|
90
92
|
end
|
91
93
|
end
|
92
94
|
|
93
95
|
def clean_css(css)
|
94
|
-
css.gsub(CLEANING_MATCHER,
|
96
|
+
css.gsub(CLEANING_MATCHER, "")
|
95
97
|
end
|
96
98
|
|
97
99
|
def should_find_external?
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# @api public
|
3
5
|
# The {CachedProvider} wraps another provider (or {ProviderList}) and caches
|
@@ -67,6 +69,7 @@ module Roadie
|
|
67
69
|
end
|
68
70
|
|
69
71
|
private
|
72
|
+
|
70
73
|
def cache_fetch(name)
|
71
74
|
cache[name] || cache[name] = yield
|
72
75
|
rescue CssNotFound
|
data/lib/roadie/deduplicator.rb
CHANGED
data/lib/roadie/document.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# The main entry point for Roadie. A document represents a working unit and
|
3
5
|
# is built with the input HTML and the configuration options you need.
|
@@ -50,7 +52,7 @@ module Roadie
|
|
50
52
|
@html = html
|
51
53
|
@asset_providers = ProviderList.wrap(FilesystemProvider.new)
|
52
54
|
@external_asset_providers = ProviderList.empty
|
53
|
-
@css = ""
|
55
|
+
@css = +""
|
54
56
|
@mode = :html
|
55
57
|
end
|
56
58
|
|
@@ -140,6 +142,7 @@ module Roadie
|
|
140
142
|
# Valid modes:
|
141
143
|
# `:html` (default)
|
142
144
|
# `:xhtml`
|
145
|
+
# `:xml`
|
143
146
|
def mode=(mode)
|
144
147
|
if VALID_MODES.include?(mode)
|
145
148
|
@mode = mode
|
@@ -149,7 +152,8 @@ module Roadie
|
|
149
152
|
end
|
150
153
|
|
151
154
|
private
|
152
|
-
|
155
|
+
|
156
|
+
VALID_MODES = %i[html xhtml xml].freeze
|
153
157
|
private_constant :VALID_MODES
|
154
158
|
|
155
159
|
def stylesheet
|
@@ -166,7 +170,7 @@ module Roadie
|
|
166
170
|
Inliner.new(dom_stylesheets + [stylesheet], dom).inline(
|
167
171
|
keep_uninlinable_css: keep_uninlinable_css,
|
168
172
|
keep_uninlinable_in: keep_uninlinable_in,
|
169
|
-
merge_media_queries: merge_media_queries
|
173
|
+
merge_media_queries: merge_media_queries
|
170
174
|
)
|
171
175
|
end
|
172
176
|
|
@@ -180,6 +184,7 @@ module Roadie
|
|
180
184
|
format = {
|
181
185
|
html: save_options::AS_HTML,
|
182
186
|
xhtml: save_options::AS_XHTML,
|
187
|
+
xml: save_options::AS_XML
|
183
188
|
}.fetch(mode)
|
184
189
|
|
185
190
|
dom.dup.to_html(
|
@@ -187,7 +192,7 @@ module Roadie
|
|
187
192
|
save_options::NO_DECLARATION |
|
188
193
|
save_options::NO_EMPTY_TAGS |
|
189
194
|
format
|
190
|
-
)
|
195
|
+
)
|
191
196
|
)
|
192
197
|
end
|
193
198
|
|
@@ -201,13 +206,7 @@ module Roadie
|
|
201
206
|
|
202
207
|
def callback(callable, dom)
|
203
208
|
if callable.respond_to?(:call)
|
204
|
-
|
205
|
-
# TODO: Remove on next major version (v4.0)
|
206
|
-
if !callable.respond_to?(:parameters) || callable.parameters.size == 1
|
207
|
-
callable.(dom)
|
208
|
-
else
|
209
|
-
callable.(dom, self)
|
210
|
-
end
|
209
|
+
callable.call(dom, self)
|
211
210
|
end
|
212
211
|
end
|
213
212
|
|
data/lib/roadie/errors.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# Base class for all Roadie errors. Rescue this if you want to catch errors
|
3
5
|
# from Roadie.
|
@@ -16,10 +18,10 @@ module Roadie
|
|
16
18
|
|
17
19
|
def initialize(given_path, cause = nil)
|
18
20
|
@cause = cause
|
19
|
-
if cause
|
20
|
-
|
21
|
+
cause_message = if cause
|
22
|
+
" Caused by: #{cause}"
|
21
23
|
else
|
22
|
-
|
24
|
+
""
|
23
25
|
end
|
24
26
|
super "Cannot use path \"#{given_path}\" in URL generation.#{cause_message}"
|
25
27
|
end
|
@@ -41,24 +43,23 @@ module Roadie
|
|
41
43
|
# Extra message
|
42
44
|
attr_reader :extra_message
|
43
45
|
|
44
|
-
|
45
|
-
def initialize(css_name, extra_message = nil, provider = nil)
|
46
|
+
def initialize(css_name:, message: nil, provider: nil)
|
46
47
|
@css_name = css_name
|
47
48
|
@provider = provider
|
48
|
-
@extra_message =
|
49
|
-
super build_message
|
49
|
+
@extra_message = message
|
50
|
+
super build_message
|
50
51
|
end
|
51
52
|
|
52
53
|
protected
|
54
|
+
|
53
55
|
def error_row
|
54
|
-
"#{provider || "Unknown provider"}: #{extra_message
|
56
|
+
"#{provider || "Unknown provider"}: #{extra_message}"
|
55
57
|
end
|
56
58
|
|
57
59
|
private
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
message = %(Could not find stylesheet "#{css_name}")
|
60
|
+
|
61
|
+
def build_message
|
62
|
+
message = +%(Could not find stylesheet "#{css_name}")
|
62
63
|
message << ": #{extra_message}" if extra_message
|
63
64
|
message << "\nUsed provider:\n#{provider}" if provider
|
64
65
|
message
|
@@ -68,14 +69,19 @@ module Roadie
|
|
68
69
|
class ProvidersFailed < CssNotFound
|
69
70
|
attr_reader :errors
|
70
71
|
|
71
|
-
def initialize(css_name
|
72
|
+
def initialize(css_name:, providers:, errors:)
|
72
73
|
@errors = errors
|
73
|
-
super(
|
74
|
+
super(
|
75
|
+
css_name: css_name,
|
76
|
+
message: "All providers failed",
|
77
|
+
provider: providers
|
78
|
+
)
|
74
79
|
end
|
75
80
|
|
76
81
|
private
|
77
|
-
|
78
|
-
|
82
|
+
|
83
|
+
def build_message
|
84
|
+
message = +%(Could not find stylesheet "#{css_name}": #{extra_message}\nUsed providers:\n)
|
79
85
|
each_error_row(errors) do |row|
|
80
86
|
message << "\t" << row << "\n"
|
81
87
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roadie
|
2
4
|
# Asset provider that looks for files on your local filesystem.
|
3
5
|
#
|
@@ -30,14 +32,24 @@ module Roadie
|
|
30
32
|
Stylesheet.new file_path, File.read(file_path)
|
31
33
|
else
|
32
34
|
basename = File.basename file_path
|
33
|
-
raise CssNotFound.new(
|
35
|
+
raise CssNotFound.new(
|
36
|
+
css_name: basename,
|
37
|
+
message: %{#{file_path} does not exist. (Original name was "#{name}")},
|
38
|
+
provider: self
|
39
|
+
)
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
37
|
-
def to_s
|
38
|
-
|
43
|
+
def to_s
|
44
|
+
inspect
|
45
|
+
end
|
46
|
+
|
47
|
+
def inspect
|
48
|
+
"#<#{self.class} #{@path}>"
|
49
|
+
end
|
39
50
|
|
40
51
|
private
|
52
|
+
|
41
53
|
def build_file_path(name)
|
42
54
|
raise InsecurePathError, name if name.include?("..")
|
43
55
|
File.join(@path, name[/^([^?]+)/])
|
data/lib/roadie/inliner.rb
CHANGED
@@ -1,19 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "nokogiri"
|
5
|
+
require "uri"
|
6
|
+
require "css_parser"
|
5
7
|
|
6
8
|
module Roadie
|
7
9
|
# @api private
|
8
10
|
# The Inliner inlines stylesheets to the elements of the DOM.
|
9
11
|
#
|
10
12
|
# Inlining means that {StyleBlock}s and a DOM tree are combined:
|
11
|
-
#
|
12
|
-
#
|
13
|
+
#
|
14
|
+
# ```css
|
15
|
+
# a { color: red; } # StyleBlock
|
16
|
+
# ```
|
17
|
+
# ```html
|
18
|
+
# <a href="/"></a> # DOM
|
19
|
+
# ```
|
13
20
|
#
|
14
21
|
# becomes
|
15
22
|
#
|
16
|
-
#
|
23
|
+
# ```html
|
24
|
+
# <a href="/" style="color:red"></a>
|
25
|
+
# ```
|
17
26
|
class Inliner
|
18
27
|
# @param [Array<Stylesheet>] stylesheets the stylesheets to use in the inlining
|
19
28
|
# @param [Nokogiri::HTML::Document] dom
|
@@ -45,9 +54,11 @@ module Roadie
|
|
45
54
|
end
|
46
55
|
|
47
56
|
protected
|
57
|
+
|
48
58
|
attr_reader :stylesheets, :dom
|
49
59
|
|
50
60
|
private
|
61
|
+
|
51
62
|
def consume_stylesheets
|
52
63
|
style_map = StyleMap.new
|
53
64
|
extra_blocks = []
|
@@ -89,12 +100,18 @@ module Roadie
|
|
89
100
|
# with having to rescue errors.
|
90
101
|
# Pseudo selectors that are known to be bad are skipped automatically but
|
91
102
|
# this will catch the rest.
|
92
|
-
rescue Nokogiri::XML::XPath::SyntaxError, Nokogiri::CSS::SyntaxError
|
93
|
-
Utils.warn
|
103
|
+
rescue Nokogiri::XML::XPath::SyntaxError, Nokogiri::CSS::SyntaxError
|
104
|
+
Utils.warn(
|
105
|
+
"Cannot inline #{selector.inspect} from \"#{stylesheet.name}\" " \
|
106
|
+
"stylesheet. If this is valid CSS, please report a bug."
|
107
|
+
)
|
94
108
|
nil
|
95
109
|
rescue => error
|
96
|
-
Utils.warn
|
97
|
-
|
110
|
+
Utils.warn(
|
111
|
+
"Got error when looking for #{selector.inspect} " \
|
112
|
+
"(from \"#{stylesheet.name}\" stylesheet): #{error}"
|
113
|
+
)
|
114
|
+
raise unless error.message.include?("XPath")
|
98
115
|
nil
|
99
116
|
end
|
100
117
|
|
@@ -120,12 +137,12 @@ module Roadie
|
|
120
137
|
end
|
121
138
|
|
122
139
|
def find_head
|
123
|
-
dom.at_xpath(
|
140
|
+
dom.at_xpath("html/head")
|
124
141
|
end
|
125
142
|
|
126
143
|
def create_style_element(style_blocks, parent, merge_media_queries)
|
127
144
|
return unless parent
|
128
|
-
element = Nokogiri::XML::Node.new(
|
145
|
+
element = Nokogiri::XML::Node.new("style", parent.document)
|
129
146
|
|
130
147
|
element.content =
|
131
148
|
if merge_media_queries
|
@@ -139,17 +156,23 @@ module Roadie
|
|
139
156
|
# For performance reasons, we should group styles with the same media types within
|
140
157
|
# one media query instead of creating thousands of media queries.
|
141
158
|
# https://github.com/artifex404/media-queries-benchmark
|
142
|
-
#
|
159
|
+
#
|
160
|
+
# Example result:
|
161
|
+
#
|
162
|
+
# ```ruby
|
163
|
+
# ["@media(max-width: 600px) { .col-12 { display: block; } }"]
|
164
|
+
# ```
|
165
|
+
#
|
143
166
|
# @param {Array<StyleBlock>} style_blocks Style blocks that could not be inlined
|
144
167
|
# @return {Array<String>}
|
145
168
|
def styles_in_shared_media_queries(style_blocks)
|
146
169
|
style_blocks.group_by(&:media).map do |media_types, blocks|
|
147
170
|
css_rules = blocks.map(&:to_s).join("\n")
|
148
171
|
|
149
|
-
if media_types == [
|
172
|
+
if media_types == ["all"]
|
150
173
|
css_rules
|
151
174
|
else
|
152
|
-
"@media #{media_types.join(
|
175
|
+
"@media #{media_types.join(", ")} {\n#{css_rules}\n}"
|
153
176
|
end
|
154
177
|
end
|
155
178
|
end
|
@@ -157,27 +180,36 @@ module Roadie
|
|
157
180
|
# Some users might prefer to not group rules within media queries because
|
158
181
|
# it will result in rules getting reordered.
|
159
182
|
# e.g.
|
183
|
+
#
|
184
|
+
# ```css
|
160
185
|
# @media(max-width: 600px) { .col-6 { display: block; } }
|
161
186
|
# @media(max-width: 400px) { .col-12 { display: inline-block; } }
|
162
187
|
# @media(max-width: 600px) { .col-12 { display: block; } }
|
188
|
+
# ````
|
189
|
+
#
|
163
190
|
# will become
|
191
|
+
#
|
192
|
+
# ```css
|
164
193
|
# @media(max-width: 600px) { .col-6 { display: block; } .col-12 { display: block; } }
|
165
194
|
# @media(max-width: 400px) { .col-12 { display: inline-block; } }
|
195
|
+
# ```
|
196
|
+
#
|
197
|
+
#
|
166
198
|
# which would change the styling on the page
|
167
199
|
# (before it would've yielded display: block; for .col-12 at max-width: 600px
|
168
200
|
# and now it yields inline-block;)
|
169
201
|
#
|
170
202
|
# If merge_media_queries is set to false,
|
171
|
-
# we will generate
|
203
|
+
# we will generate `style_blocks.size` media queries, potentially
|
172
204
|
# causing performance issues.
|
173
205
|
# @param {Array<StyleBlock>} style_blocks All style blocks
|
174
206
|
# @return {Array<String>}
|
175
207
|
def styles_in_individual_media_queries(style_blocks)
|
176
208
|
style_blocks.map do |css_rule|
|
177
|
-
if css_rule.media == [
|
209
|
+
if css_rule.media == ["all"]
|
178
210
|
css_rule
|
179
211
|
else
|
180
|
-
"@media #{css_rule.media.join(
|
212
|
+
"@media #{css_rule.media.join(", ")} {\n#{css_rule}\n}"
|
181
213
|
end
|
182
214
|
end
|
183
215
|
end
|