premailer 1.24.0 → 1.25.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/bin/premailer +1 -1
- data/lib/premailer/adapter/nokogiri.rb +6 -4
- data/lib/premailer/adapter/nokogiri_fast.rb +8 -6
- data/lib/premailer/adapter/nokogumbo.rb +6 -4
- data/lib/premailer/adapter/rgb_to_hex.rb +1 -0
- data/lib/premailer/adapter.rb +4 -3
- data/lib/premailer/cached_rule_set.rb +1 -0
- data/lib/premailer/executor.rb +5 -4
- data/lib/premailer/html_to_plain_text.rb +3 -2
- data/lib/premailer/premailer.rb +19 -19
- data/lib/premailer/version.rb +2 -1
- data/lib/premailer.rb +1 -0
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d8f189b10e7c9868d3abeae3d057e0b0681bb7798c0fbd7e8fe3aa8bb922aad
|
4
|
+
data.tar.gz: e0dbb8d0d65aeb0ec7e463983148b1c54f77fa005fd73766a749ee147a12d240
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 650e617eefd069d1733092612fa4eb434b539564f61f81fcbda4c7a06121fc3d8a71ee440ce5dfee3e0f97f88282e4dcd1da6c33bddcd4008d05f0ebb4aa82a6
|
7
|
+
data.tar.gz: c537248adafbc5f6ed58f8825055fe557098c1bea88240c4ec08d5d248268fb3f45db365cf08912a693dd963abe0825f942f5b5937553ceeacd54a51f1f44f21
|
data/bin/premailer
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'nokogiri'
|
2
3
|
|
3
4
|
class Premailer
|
4
5
|
module Adapter
|
5
6
|
# Nokogiri adapter
|
6
7
|
module Nokogiri
|
8
|
+
WIDTH_AND_HIGHT = ['width', 'height'].freeze
|
7
9
|
|
8
10
|
include AdapterHelper::RgbToHex
|
9
11
|
# Merge CSS into the HTML document.
|
@@ -30,7 +32,7 @@ class Premailer
|
|
30
32
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
31
33
|
else
|
32
34
|
begin
|
33
|
-
if
|
35
|
+
if Premailer::RE_RESET_SELECTORS.match?(selector)
|
34
36
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
35
37
|
# however, this doesn't mean for testing pur
|
36
38
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
@@ -90,7 +92,7 @@ class Premailer
|
|
90
92
|
new_val.gsub!(/;$|\s*!important/, '').strip!
|
91
93
|
|
92
94
|
# For width and height tags, remove px units
|
93
|
-
new_val.gsub!(/(\d+)px/, '\1') if
|
95
|
+
new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HIGHT.include?(html_attr)
|
94
96
|
|
95
97
|
# For color-related tags, convert RGB to hex if specified by options
|
96
98
|
new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
|
@@ -99,7 +101,7 @@ class Premailer
|
|
99
101
|
end
|
100
102
|
|
101
103
|
unless @options[:preserve_style_attribute]
|
102
|
-
merged.instance_variable_get(
|
104
|
+
merged.instance_variable_get(:@declarations).tap do |declarations|
|
103
105
|
declarations.delete(css_attr)
|
104
106
|
end
|
105
107
|
end
|
@@ -250,7 +252,7 @@ class Premailer
|
|
250
252
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
251
253
|
# https://github.com/sparklemotion/nokogiri/issues/311 and
|
252
254
|
# https://github.com/premailer/premailer/issues/199
|
253
|
-
|
255
|
+
['style', 'script'].each do |tag|
|
254
256
|
doc.search(tag).children.each do |child|
|
255
257
|
child.swap(child.text()) if child.cdata?
|
256
258
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'nokogiri'
|
2
3
|
|
3
4
|
class Premailer
|
4
5
|
module Adapter
|
5
6
|
# NokogiriFast adapter
|
6
7
|
module NokogiriFast
|
8
|
+
WIDTH_AND_HEIGHT = ['width', 'height'].freeze
|
7
9
|
|
8
10
|
include AdapterHelper::RgbToHex
|
9
11
|
# Merge CSS into the HTML document.
|
@@ -36,7 +38,7 @@ class Premailer
|
|
36
38
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
37
39
|
else
|
38
40
|
begin
|
39
|
-
if
|
41
|
+
if Premailer::RE_RESET_SELECTORS.match?(selector)
|
40
42
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
41
43
|
# however, this doesn't mean for testing pur
|
42
44
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
@@ -96,7 +98,7 @@ class Premailer
|
|
96
98
|
new_val.gsub!(/;$|\s*!important/, '').strip!
|
97
99
|
|
98
100
|
# For width and height tags, remove px units
|
99
|
-
new_val.gsub!(/(\d+)px/, '\1') if
|
101
|
+
new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HEIGHT.include?(html_attr)
|
100
102
|
|
101
103
|
# For color-related tags, convert RGB to hex if specified by options
|
102
104
|
new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
|
@@ -105,7 +107,7 @@ class Premailer
|
|
105
107
|
end
|
106
108
|
|
107
109
|
unless @options[:preserve_style_attribute]
|
108
|
-
merged.instance_variable_get(
|
110
|
+
merged.instance_variable_get(:@declarations).tap do |declarations|
|
109
111
|
declarations.delete(css_attr)
|
110
112
|
end
|
111
113
|
end
|
@@ -255,7 +257,7 @@ class Premailer
|
|
255
257
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
256
258
|
# https://github.com/sparklemotion/nokogiri/issues/311 and
|
257
259
|
# https://github.com/premailer/premailer/issues/199
|
258
|
-
|
260
|
+
['style', 'script'].each do |tag|
|
259
261
|
doc.search(tag).children.each do |child|
|
260
262
|
child.swap(child.text()) if child.cdata?
|
261
263
|
end
|
@@ -314,7 +316,7 @@ class Premailer
|
|
314
316
|
index.default = Set.new
|
315
317
|
descendants.default = Set.new
|
316
318
|
|
317
|
-
|
319
|
+
[index, Set.new(all_nodes), descendants]
|
318
320
|
end
|
319
321
|
|
320
322
|
# @param doc The top level document
|
@@ -354,7 +356,7 @@ class Premailer
|
|
354
356
|
# It will return nil when such a selector is passed, so you can take
|
355
357
|
# action on the falsity of the return value.
|
356
358
|
def match_selector(index, all_nodes, descendants, selector)
|
357
|
-
if /[^-a-zA-Z0-9_\s.#]/.match(selector) then
|
359
|
+
if /[^-a-zA-Z0-9_\s.#]/.match?(selector) then
|
358
360
|
return nil
|
359
361
|
end
|
360
362
|
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class Premailer
|
2
3
|
module Adapter
|
3
4
|
# Nokogiri adapter
|
4
5
|
module Nokogumbo
|
6
|
+
WIDTH_AND_HEIGHT = ['width', 'height'].freeze
|
5
7
|
|
6
8
|
include AdapterHelper::RgbToHex
|
7
9
|
# Merge CSS into the HTML document.
|
@@ -28,7 +30,7 @@ class Premailer
|
|
28
30
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration), media_types) unless @options[:preserve_styles]
|
29
31
|
else
|
30
32
|
begin
|
31
|
-
if
|
33
|
+
if Premailer::RE_RESET_SELECTORS.match?(selector)
|
32
34
|
# this is in place to preserve the MailChimp CSS reset: http://github.com/mailchimp/Email-Blueprints/
|
33
35
|
# however, this doesn't mean for testing pur
|
34
36
|
@unmergable_rules.add_rule_set!(CssParser::RuleSet.new(selector, declaration)) unless !@options[:preserve_reset]
|
@@ -90,7 +92,7 @@ class Premailer
|
|
90
92
|
new_val.gsub!(/;$|\s*!important/, '').strip!
|
91
93
|
|
92
94
|
# For width and height tags, remove px units
|
93
|
-
new_val.gsub!(/(\d+)px/, '\1') if
|
95
|
+
new_val.gsub!(/(\d+)px/, '\1') if WIDTH_AND_HEIGHT.include?(html_attr)
|
94
96
|
|
95
97
|
# For color-related tags, convert RGB to hex if specified by options
|
96
98
|
new_val = ensure_hex(new_val) if css_attr.end_with?('color') && @options[:rgb_to_hex_attributes]
|
@@ -99,7 +101,7 @@ class Premailer
|
|
99
101
|
end
|
100
102
|
|
101
103
|
unless @options[:preserve_style_attribute]
|
102
|
-
merged.instance_variable_get(
|
104
|
+
merged.instance_variable_get(:@declarations).tap do |declarations|
|
103
105
|
declarations.delete(css_attr)
|
104
106
|
end
|
105
107
|
end
|
@@ -248,7 +250,7 @@ class Premailer
|
|
248
250
|
# Fix for removing any CDATA tags from both style and script tags inserted per
|
249
251
|
# https://github.com/sparklemotion/nokogiri/issues/311 and
|
250
252
|
# https://github.com/premailer/premailer/issues/199
|
251
|
-
|
253
|
+
['style', 'script'].each do |tag|
|
252
254
|
doc.search(tag).children.each do |child|
|
253
255
|
child.swap(child.text()) if child.cdata?
|
254
256
|
end
|
data/lib/premailer/adapter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class Premailer
|
2
3
|
# Manages the adapter classes. Currently supports:
|
3
4
|
#
|
@@ -14,7 +15,7 @@ class Premailer
|
|
14
15
|
REQUIREMENT_MAP = [
|
15
16
|
["nokogiri", :nokogiri],
|
16
17
|
["nokogiri", :nokogiri_fast],
|
17
|
-
["nokogumbo", :nokogumbo]
|
18
|
+
["nokogumbo", :nokogumbo]
|
18
19
|
]
|
19
20
|
|
20
21
|
# Returns the adapter to use.
|
@@ -42,7 +43,7 @@ class Premailer
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
raise
|
46
|
+
raise "No suitable adapter for Premailer was found, please install nokogiri or nokogumbo"
|
46
47
|
end
|
47
48
|
|
48
49
|
# Sets the adapter to use.
|
@@ -56,7 +57,7 @@ class Premailer
|
|
56
57
|
def self.find(adapter)
|
57
58
|
return adapter if adapter.is_a?(Module)
|
58
59
|
|
59
|
-
Premailer::Adapter.const_get("#{adapter.to_s.split('_').map{|s| s.capitalize}.join
|
60
|
+
Premailer::Adapter.const_get("#{adapter.to_s.split('_').map{|s| s.capitalize}.join}")
|
60
61
|
rescue NameError
|
61
62
|
raise ArgumentError, "Invalid adapter: #{adapter}"
|
62
63
|
end
|
data/lib/premailer/executor.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'optparse'
|
2
3
|
require 'premailer'
|
3
4
|
|
@@ -8,12 +9,12 @@ options = {
|
|
8
9
|
:remove_classes => false,
|
9
10
|
:verbose => false,
|
10
11
|
:line_length => 65,
|
11
|
-
:adapter => :nokogiri
|
12
|
+
:adapter => :nokogiri
|
12
13
|
}
|
13
14
|
|
14
15
|
mode = :html
|
15
16
|
|
16
|
-
|
17
|
+
parser = OptionParser.new do |opts|
|
17
18
|
opts.banner = "Improve the rendering of HTML emails by making CSS inline among other things. Takes a path to a local file, a URL or a pipe as input.\n\n"
|
18
19
|
opts.define_head "Usage: premailer <optional uri|optional path> [options]"
|
19
20
|
opts.separator ""
|
@@ -79,7 +80,7 @@ opts = OptionParser.new do |opts|
|
|
79
80
|
exit
|
80
81
|
end
|
81
82
|
end
|
82
|
-
|
83
|
+
parser.parse!
|
83
84
|
|
84
85
|
$stderr.puts "Processing in #{mode} mode with options #{options.inspect}" if options[:verbose]
|
85
86
|
|
@@ -98,7 +99,7 @@ end
|
|
98
99
|
if input
|
99
100
|
premailer = Premailer.new(input, options)
|
100
101
|
else
|
101
|
-
puts
|
102
|
+
puts parser
|
102
103
|
exit 1
|
103
104
|
end
|
104
105
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'htmlentities'
|
3
4
|
|
4
5
|
# Support functions for Premailer
|
@@ -13,7 +14,7 @@ module HtmlToPlainText
|
|
13
14
|
#
|
14
15
|
# TODO: add support for DL, OL
|
15
16
|
# TODO: this is not safe and needs a real html parser to work
|
16
|
-
def convert_to_text(html, line_length = 65,
|
17
|
+
def convert_to_text(html, line_length = 65, _from_charset = 'UTF-8')
|
17
18
|
txt = +html
|
18
19
|
|
19
20
|
# strip text ignored html. Useful for removing
|
@@ -50,7 +51,7 @@ module HtmlToPlainText
|
|
50
51
|
|
51
52
|
if text.empty?
|
52
53
|
''
|
53
|
-
elsif href.nil? || text.strip.
|
54
|
+
elsif href.nil? || text.strip.casecmp(href.strip) == 0
|
54
55
|
text.strip
|
55
56
|
else
|
56
57
|
text.strip + ' ( ' + href.strip + ' )'
|
data/lib/premailer/premailer.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# Premailer processes HTML and CSS to improve e-mail deliverability.
|
2
3
|
#
|
3
4
|
# Premailer's main function is to render all CSS as inline <tt>style</tt>
|
@@ -141,7 +142,7 @@ class Premailer
|
|
141
142
|
include Warnings
|
142
143
|
|
143
144
|
# Waning level names
|
144
|
-
WARN_LABEL =
|
145
|
+
WARN_LABEL = ['NONE', 'SAFE', 'POOR', 'RISKY']
|
145
146
|
|
146
147
|
# Create a new Premailer object.
|
147
148
|
#
|
@@ -212,8 +213,7 @@ class Premailer
|
|
212
213
|
:create_shorthands => true,
|
213
214
|
:html_fragment => false,
|
214
215
|
:adapter => Adapter.use,
|
215
|
-
:drop_unmergeable_css_rules => false
|
216
|
-
}.merge(options)
|
216
|
+
:drop_unmergeable_css_rules => false}.merge(options)
|
217
217
|
|
218
218
|
@html_file = html
|
219
219
|
@is_local_file = @options[:with_html_string] || Premailer.local_data?(html)
|
@@ -265,10 +265,10 @@ class Premailer
|
|
265
265
|
protected
|
266
266
|
def load_css_from_local_file!(path)
|
267
267
|
css_block = +''
|
268
|
-
path.
|
268
|
+
path.delete_prefix!('file:')
|
269
269
|
begin
|
270
270
|
File.open(path, "r") do |file|
|
271
|
-
while line = file.gets
|
271
|
+
while (line = file.gets)
|
272
272
|
css_block << line
|
273
273
|
end
|
274
274
|
end
|
@@ -355,12 +355,12 @@ public
|
|
355
355
|
media_types.split(/[\s]+|,/).any? { |media_type| media_type.strip =~ /screen|handheld|all/i }
|
356
356
|
end
|
357
357
|
|
358
|
-
def append_query_string(doc,
|
359
|
-
return doc if
|
358
|
+
def append_query_string(doc, queries)
|
359
|
+
return doc if queries.nil?
|
360
360
|
|
361
|
-
|
362
|
-
|
363
|
-
return doc if
|
361
|
+
queries = +queries
|
362
|
+
queries.to_s.gsub!(/^[\?]*/, '').strip!
|
363
|
+
return doc if queries.empty?
|
364
364
|
|
365
365
|
begin
|
366
366
|
current_host = @base_url.host
|
@@ -368,18 +368,18 @@ public
|
|
368
368
|
current_host = nil
|
369
369
|
end
|
370
370
|
|
371
|
-
$stderr.puts "Attempting to append_query_string: #{
|
371
|
+
$stderr.puts "Attempting to append_query_string: #{queries}" if @options[:verbose]
|
372
372
|
|
373
|
-
doc.search('a').each do|el|
|
373
|
+
doc.search('a').each do |el|
|
374
374
|
href = el.attributes['href'].to_s.strip
|
375
375
|
next if href.nil? or href.empty?
|
376
376
|
|
377
|
-
next if
|
377
|
+
next if /[\#\{\[\<\%]/.match?(href[0,1]) # don't bother with anchors or special-looking links
|
378
378
|
|
379
379
|
begin
|
380
380
|
href = Addressable::URI.parse(href)
|
381
381
|
|
382
|
-
if current_host and href.host
|
382
|
+
if current_host and !href.host.nil? and href.host != current_host
|
383
383
|
$stderr.puts "Skipping append_query_string for: #{href.to_s} because host is no good" if @options[:verbose]
|
384
384
|
next
|
385
385
|
end
|
@@ -391,9 +391,9 @@ public
|
|
391
391
|
|
392
392
|
if href.query and not href.query.empty?
|
393
393
|
amp = @options[:unescaped_ampersand] ? '&' : '&'
|
394
|
-
href.query = href.query + amp +
|
394
|
+
href.query = href.query + amp + queries
|
395
395
|
else
|
396
|
-
href.query =
|
396
|
+
href.query = queries
|
397
397
|
end
|
398
398
|
|
399
399
|
el['href'] = href.to_s
|
@@ -436,11 +436,11 @@ public
|
|
436
436
|
tags.each do |tag|
|
437
437
|
# skip links that look like they have merge tags
|
438
438
|
# and mailto, ftp, etc...
|
439
|
-
if
|
439
|
+
if /^([\%\<\{\#\[]|data:|tel:|file:|sms:|callto:|facetime:|mailto:|ftp:|gopher:|cid:)/i.match?(tag.attributes[attribute].to_s)
|
440
440
|
next
|
441
441
|
end
|
442
442
|
|
443
|
-
if tag.attributes[attribute].to_s
|
443
|
+
if /^http/i.match?(tag.attributes[attribute].to_s)
|
444
444
|
begin
|
445
445
|
merged = Addressable::URI.parse(tag.attributes[attribute])
|
446
446
|
rescue; next; end
|
@@ -477,7 +477,7 @@ public
|
|
477
477
|
path = +path
|
478
478
|
path.strip!
|
479
479
|
resolved = nil
|
480
|
-
if
|
480
|
+
if /\A(?:(https?|ftp|file):)\/\//i.match?(path)
|
481
481
|
resolved = path
|
482
482
|
Premailer.canonicalize(resolved)
|
483
483
|
elsif base_path.kind_of?(Addressable::URI)
|
data/lib/premailer/version.rb
CHANGED
data/lib/premailer.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: premailer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.25.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Dunae
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: css_parser
|
@@ -129,7 +129,7 @@ dependencies:
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
132
|
+
name: webmock
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - ">="
|
@@ -143,7 +143,7 @@ dependencies:
|
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '0'
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
|
-
name:
|
146
|
+
name: bump
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
148
148
|
requirements:
|
149
149
|
- - ">="
|
@@ -157,7 +157,21 @@ dependencies:
|
|
157
157
|
- !ruby/object:Gem::Version
|
158
158
|
version: '0'
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
|
-
name:
|
160
|
+
name: rubocop
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 1.62.1
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 1.62.1
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: rubocop-performance
|
161
175
|
requirement: !ruby/object:Gem::Requirement
|
162
176
|
requirements:
|
163
177
|
- - ">="
|