mjml-rb 0.5.2 → 0.6.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/CHANGELOG.md +29 -0
- data/README.md +60 -22
- data/THIRD_PARTY_LICENSES.md +25 -0
- data/docs/ARCHITECTURE.md +363 -0
- data/docs/MIGRATING_TO_V5.md +112 -0
- data/docs/MJML_V5_SUPPORT_PLAN.md +325 -0
- data/docs/PARITY_AUDIT.md +124 -0
- data/docs/RELEASING.md +35 -0
- data/docs/USAGE.md +1258 -0
- data/docs/releases/v0.6.0.md +63 -0
- data/lib/mjml-rb/cli.rb +43 -31
- data/lib/mjml-rb/column_gutter.rb +81 -0
- data/lib/mjml-rb/compiler.rb +32 -122
- data/lib/mjml-rb/component_registry.rb +11 -1
- data/lib/mjml-rb/components/accordion.rb +11 -9
- data/lib/mjml-rb/components/base.rb +1 -1
- data/lib/mjml-rb/components/body.rb +6 -3
- data/lib/mjml-rb/components/carousel.rb +2 -2
- data/lib/mjml-rb/components/carousel_image.rb +2 -2
- data/lib/mjml-rb/components/column.rb +16 -11
- data/lib/mjml-rb/components/group.rb +13 -4
- data/lib/mjml-rb/components/hero.rb +7 -2
- data/lib/mjml-rb/components/image.rb +1 -3
- data/lib/mjml-rb/components/raw.rb +1 -1
- data/lib/mjml-rb/components/section.rb +23 -8
- data/lib/mjml-rb/components/social.rb +18 -27
- data/lib/mjml-rb/components/table.rb +1 -1
- data/lib/mjml-rb/config_file.rb +25 -15
- data/lib/mjml-rb/dependencies.rb +1 -0
- data/lib/mjml-rb/formatter.rb +113 -0
- data/lib/mjml-rb/node_compat.rb +4 -0
- data/lib/mjml-rb/options.rb +81 -0
- data/lib/mjml-rb/parser.rb +138 -94
- data/lib/mjml-rb/renderer.rb +50 -76
- data/lib/mjml-rb/result.rb +3 -2
- data/lib/mjml-rb/validator.rb +14 -33
- data/lib/mjml-rb/version.rb +2 -1
- data/lib/mjml-rb.rb +2 -2
- data/mjml-rb.gemspec +2 -2
- metadata +19 -1
data/lib/mjml-rb/renderer.rb
CHANGED
|
@@ -64,6 +64,7 @@ module MjmlRb
|
|
|
64
64
|
HTML
|
|
65
65
|
|
|
66
66
|
def render(document, options = {})
|
|
67
|
+
@formatting = options[:minify] || options[:beautify]
|
|
67
68
|
head = find_child(document, "mj-head")
|
|
68
69
|
body = find_child(document, "mj-body")
|
|
69
70
|
raise ArgumentError, "Missing <mj-body>" unless body
|
|
@@ -84,6 +85,8 @@ module MjmlRb
|
|
|
84
85
|
|
|
85
86
|
def build_context(head, options)
|
|
86
87
|
context = {
|
|
88
|
+
sanitize_styles: options[:sanitize_styles],
|
|
89
|
+
template_syntax: options[:template_syntax] || Options::DEFAULTS[:template_syntax],
|
|
87
90
|
title: "",
|
|
88
91
|
preview: "",
|
|
89
92
|
breakpoint: "480px",
|
|
@@ -115,7 +118,6 @@ module MjmlRb
|
|
|
115
118
|
content = minify_outlook_conditionals(content)
|
|
116
119
|
content = apply_html_attributes_to_content(content, context)
|
|
117
120
|
title = context[:title].to_s
|
|
118
|
-
preview = context[:preview]
|
|
119
121
|
head_raw = Array(context[:head_raw]).join("\n")
|
|
120
122
|
before_doctype = context[:before_doctype].to_s
|
|
121
123
|
font_tags = build_font_tags(content, context[:inline_styles], context[:fonts])
|
|
@@ -127,7 +129,6 @@ module MjmlRb
|
|
|
127
129
|
)
|
|
128
130
|
component_styles_tag = build_style_tag(unique_strings(context[:component_head_styles]))
|
|
129
131
|
user_styles_tag = build_style_tag(unique_strings(context[:user_styles]))
|
|
130
|
-
preview_block = preview.empty? ? "" : %(<div style="display:none;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">#{escape_html(preview)}</div>)
|
|
131
132
|
html_attributes = {
|
|
132
133
|
"lang" => context[:lang],
|
|
133
134
|
"dir" => context[:dir],
|
|
@@ -135,10 +136,6 @@ module MjmlRb
|
|
|
135
136
|
"xmlns:v" => "urn:schemas-microsoft-com:vml",
|
|
136
137
|
"xmlns:o" => "urn:schemas-microsoft-com:office:office"
|
|
137
138
|
}
|
|
138
|
-
body_style = style_join(
|
|
139
|
-
"word-spacing" => "normal",
|
|
140
|
-
"background-color" => context[:background_color]
|
|
141
|
-
)
|
|
142
139
|
|
|
143
140
|
html = <<~HTML
|
|
144
141
|
<!doctype html>
|
|
@@ -159,10 +156,7 @@ module MjmlRb
|
|
|
159
156
|
#{user_styles_tag}
|
|
160
157
|
#{head_raw}
|
|
161
158
|
</head>
|
|
162
|
-
|
|
163
|
-
#{preview_block}
|
|
164
|
-
#{content}
|
|
165
|
-
</body>
|
|
159
|
+
#{content}
|
|
166
160
|
</html>
|
|
167
161
|
HTML
|
|
168
162
|
|
|
@@ -170,7 +164,8 @@ module MjmlRb
|
|
|
170
164
|
html = preserve_raw_tag_spacing(html)
|
|
171
165
|
html = strip_internal_raw_markers(html)
|
|
172
166
|
html = merge_outlook_conditionals(html)
|
|
173
|
-
before_doctype.empty? ? html : "#{before_doctype}\n#{html}"
|
|
167
|
+
html = before_doctype.empty? ? html : "#{before_doctype}\n#{html}"
|
|
168
|
+
@formatting ? html : html.gsub(/<!--mjml-rb:raw-(?:start|end)-->/, "")
|
|
174
169
|
end
|
|
175
170
|
|
|
176
171
|
def build_font_tags(content, inline_styles, fonts)
|
|
@@ -225,7 +220,7 @@ module MjmlRb
|
|
|
225
220
|
return [100] if total == 0
|
|
226
221
|
|
|
227
222
|
widths = columns.map do |col|
|
|
228
|
-
w = col["width"]
|
|
223
|
+
w = resolved_attributes(col, context)["width"]
|
|
229
224
|
if w && w.to_s =~ /(\d+(?:\.\d+)?)\s*%/
|
|
230
225
|
$1.to_f
|
|
231
226
|
elsif w && w.to_s =~ /(\d+(?:\.\d+)?)\s*px/
|
|
@@ -236,16 +231,7 @@ module MjmlRb
|
|
|
236
231
|
end
|
|
237
232
|
end
|
|
238
233
|
|
|
239
|
-
|
|
240
|
-
unset_count = widths.count(&:nil?)
|
|
241
|
-
|
|
242
|
-
if unset_count > 0
|
|
243
|
-
remaining = [100.0 - specified, 0.0].max
|
|
244
|
-
each_unset = remaining / unset_count
|
|
245
|
-
widths.map { |w| w || each_unset }
|
|
246
|
-
else
|
|
247
|
-
widths
|
|
248
|
-
end
|
|
234
|
+
widths.map { |width| width || 100.0 / total }
|
|
249
235
|
end
|
|
250
236
|
|
|
251
237
|
def build_media_queries_tags(breakpoint, column_widths, force_owa_desktop: false, printer_support: false)
|
|
@@ -253,13 +239,13 @@ module MjmlRb
|
|
|
253
239
|
return "" if widths.empty?
|
|
254
240
|
|
|
255
241
|
base_rules = widths.map do |class_name, width_str|
|
|
256
|
-
".#{class_name} {
|
|
242
|
+
".#{class_name} { #{media_query_declarations(width_str)} }"
|
|
257
243
|
end
|
|
258
244
|
moz_rules = widths.map do |class_name, width_str|
|
|
259
|
-
".moz-text-html .#{class_name} {
|
|
245
|
+
".moz-text-html .#{class_name} { #{media_query_declarations(width_str)} }"
|
|
260
246
|
end
|
|
261
247
|
owa_rules = widths.map do |class_name, width_str|
|
|
262
|
-
"[owa] .#{class_name} {
|
|
248
|
+
"[owa] .#{class_name} { #{media_query_declarations(width_str)} }"
|
|
263
249
|
end
|
|
264
250
|
|
|
265
251
|
bp = breakpoint.to_s.strip
|
|
@@ -283,29 +269,36 @@ module MjmlRb
|
|
|
283
269
|
parts.join("\n")
|
|
284
270
|
end
|
|
285
271
|
|
|
272
|
+
def media_query_declarations(value)
|
|
273
|
+
return "padding: #{value[:padding]} !important;" if value.is_a?(Hash)
|
|
274
|
+
"width:#{value} !important; max-width: #{value};"
|
|
275
|
+
end
|
|
276
|
+
|
|
286
277
|
def build_style_tag(styles)
|
|
287
278
|
return "" if styles.empty?
|
|
288
279
|
|
|
289
280
|
"<style type=\"text/css\">#{styles.join("\n")}</style>"
|
|
290
281
|
end
|
|
291
282
|
|
|
283
|
+
def outside_raw_regions(html)
|
|
284
|
+
html.split(/(<!--mjml-rb:raw-start-->.*?<!--mjml-rb:raw-end-->)/m).map do |part|
|
|
285
|
+
part.start_with?("<!--mjml-rb:raw-start-->") ? part : yield(part)
|
|
286
|
+
end.join
|
|
287
|
+
end
|
|
288
|
+
|
|
292
289
|
def merge_outlook_conditionals(html)
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
290
|
+
outside_raw_regions(html) do |part|
|
|
291
|
+
part.gsub(/<!\[endif\]-->\s*<!--\[if mso \| IE\]>/m, "")
|
|
292
|
+
end
|
|
296
293
|
end
|
|
297
294
|
|
|
298
295
|
def minify_outlook_conditionals(html)
|
|
299
|
-
html
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
.gsub(/(^|>)(\s+)(<|$)/m, '\1\3')
|
|
306
|
-
.gsub(/\s{2,}/m, " ")
|
|
307
|
-
|
|
308
|
-
"#{prefix}#{processed}#{suffix}"
|
|
296
|
+
outside_raw_regions(html) do |part|
|
|
297
|
+
part.gsub(/(<!--\[if\s[^\]]+\]>)([\s\S]*?)(<!\[endif\]-->)/m) do
|
|
298
|
+
prefix, content, suffix = Regexp.last_match.captures
|
|
299
|
+
processed = content.gsub(/(^|>)(\s+)(<|$)/m, '\\1\\3').gsub(/\s{2,}/m, " ")
|
|
300
|
+
"#{prefix}#{processed}#{suffix}"
|
|
301
|
+
end
|
|
309
302
|
end
|
|
310
303
|
end
|
|
311
304
|
|
|
@@ -313,7 +306,7 @@ module MjmlRb
|
|
|
313
306
|
rules = context[:html_attributes] || {}
|
|
314
307
|
return content if rules.empty?
|
|
315
308
|
|
|
316
|
-
root =
|
|
309
|
+
root = Nokogiri::HTML("<html>#{content}</html>")
|
|
317
310
|
|
|
318
311
|
rules.each do |selector, attrs|
|
|
319
312
|
next if selector.empty? || attrs.empty?
|
|
@@ -325,7 +318,7 @@ module MjmlRb
|
|
|
325
318
|
end
|
|
326
319
|
end
|
|
327
320
|
|
|
328
|
-
root.
|
|
321
|
+
root.at_css("body").to_html
|
|
329
322
|
end
|
|
330
323
|
|
|
331
324
|
def html_attributes_fragment_root(content, context)
|
|
@@ -341,6 +334,9 @@ module MjmlRb
|
|
|
341
334
|
def apply_inline_styles(html, context)
|
|
342
335
|
css_blocks = unique_strings(context[:inline_styles]).reject { |css| css.nil? || css.strip.empty? }
|
|
343
336
|
return html if css_blocks.empty?
|
|
337
|
+
if context[:sanitize_styles] && css_blocks.any? { |css| context[:template_syntax].any? { |syntax| css.include?(syntax[:prefix] || syntax["prefix"]) } }
|
|
338
|
+
raise ArgumentError, "Template syntax in inline MJML CSS is unsupported; use non-inline mj-style or raw styles"
|
|
339
|
+
end
|
|
344
340
|
|
|
345
341
|
document = parse_html_document(html)
|
|
346
342
|
rules, = parse_inline_css_rules(css_blocks.join("\n"))
|
|
@@ -626,41 +622,13 @@ module MjmlRb
|
|
|
626
622
|
end
|
|
627
623
|
|
|
628
624
|
def component_registry
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
register_component(registry, Components::Attributes.new(self))
|
|
635
|
-
register_component(registry, Components::Breakpoint.new(self))
|
|
636
|
-
register_component(registry, Components::Accordion.new(self))
|
|
637
|
-
register_component(registry, Components::Button.new(self))
|
|
638
|
-
register_component(registry, Components::Carousel.new(self))
|
|
639
|
-
register_component(registry, Components::CarouselImage.new(self))
|
|
640
|
-
register_component(registry, Components::Group.new(self))
|
|
641
|
-
register_component(registry, Components::Hero.new(self))
|
|
642
|
-
register_component(registry, Components::Image.new(self))
|
|
643
|
-
register_component(registry, Components::Navbar.new(self))
|
|
644
|
-
register_component(registry, Components::Raw.new(self))
|
|
645
|
-
register_component(registry, Components::Text.new(self))
|
|
646
|
-
register_component(registry, Components::Divider.new(self))
|
|
647
|
-
register_component(registry, Components::HtmlAttributes.new(self))
|
|
648
|
-
register_component(registry, Components::Table.new(self))
|
|
649
|
-
register_component(registry, Components::Social.new(self))
|
|
650
|
-
register_component(registry, Components::Section.new(self))
|
|
651
|
-
register_component(registry, Components::Column.new(self))
|
|
652
|
-
register_component(registry, Components::Spacer.new(self))
|
|
653
|
-
|
|
654
|
-
MjmlRb.component_registry.custom_components.each do |klass|
|
|
655
|
-
register_component(registry, klass.new(self))
|
|
656
|
-
end
|
|
657
|
-
|
|
658
|
-
registry
|
|
625
|
+
registry = MjmlRb.component_registry
|
|
626
|
+
if @registry_revision != registry.revision
|
|
627
|
+
instances = {}
|
|
628
|
+
@component_registry = registry.components.transform_values { |klass| instances[klass] ||= klass.new(self) }
|
|
629
|
+
@registry_revision = registry.revision
|
|
659
630
|
end
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
def register_component(registry, component)
|
|
663
|
-
component.tags.each { |tag| registry[tag] = component }
|
|
631
|
+
@component_registry
|
|
664
632
|
end
|
|
665
633
|
|
|
666
634
|
def resolved_attributes(node, context)
|
|
@@ -708,6 +676,12 @@ module MjmlRb
|
|
|
708
676
|
end.join
|
|
709
677
|
end
|
|
710
678
|
|
|
679
|
+
def protect_raw_html(content)
|
|
680
|
+
return content if content.empty? || (!@formatting && !content.include?("<!--[if"))
|
|
681
|
+
# Use separate markers so source htmlmin:ignore regions can be nested.
|
|
682
|
+
"<!--mjml-rb:raw-start-->#{content}<!--mjml-rb:raw-end-->"
|
|
683
|
+
end
|
|
684
|
+
|
|
711
685
|
def annotate_raw_html(content)
|
|
712
686
|
return content if content.nil? || content.empty? || !content.include?("<")
|
|
713
687
|
content.gsub(/<(?!\/|!)([A-Za-z][\w:-]*)(\s[^<>]*?)?(\s*\/?)>/) do
|
|
@@ -763,7 +737,7 @@ module MjmlRb
|
|
|
763
737
|
next unless child.tag_name == "mj-raw"
|
|
764
738
|
next unless child["position"] == "file-start"
|
|
765
739
|
|
|
766
|
-
raw_inner(child)
|
|
740
|
+
protect_raw_html(raw_inner(child))
|
|
767
741
|
end.join("\n")
|
|
768
742
|
end
|
|
769
743
|
|
|
@@ -778,7 +752,7 @@ module MjmlRb
|
|
|
778
752
|
# Internal-only attributes set by the parser for metadata tracking.
|
|
779
753
|
# These are excluded from the public attributes hash; data-mjml-raw
|
|
780
754
|
# is intentionally kept because it is used by the rendering pipeline.
|
|
781
|
-
INTERNAL_ATTRIBUTES = %w[data-mjml-file data-mjml-ending-tag].freeze
|
|
755
|
+
INTERNAL_ATTRIBUTES = %w[data-mjml-file data-mjml-line data-mjml-ending-tag].freeze
|
|
782
756
|
|
|
783
757
|
def node_string_attributes(node)
|
|
784
758
|
result = {}
|
data/lib/mjml-rb/result.rb
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
module MjmlRb
|
|
2
2
|
class Result
|
|
3
|
-
attr_reader :html, :errors, :warnings
|
|
3
|
+
attr_reader :html, :errors, :warnings, :dependencies
|
|
4
4
|
|
|
5
|
-
def initialize(html: "", errors: [], warnings: [])
|
|
5
|
+
def initialize(html: "", errors: [], warnings: [], dependencies: [])
|
|
6
6
|
@html = html.to_s
|
|
7
7
|
@errors = Array(errors)
|
|
8
8
|
@warnings = Array(warnings)
|
|
9
|
+
@dependencies = Array(dependencies).freeze
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def success?
|
data/lib/mjml-rb/validator.rb
CHANGED
|
@@ -5,28 +5,31 @@ module MjmlRb
|
|
|
5
5
|
class Validator
|
|
6
6
|
GLOBAL_ALLOWED_ATTRIBUTES = %w[css-class mj-class].freeze
|
|
7
7
|
|
|
8
|
-
REQUIRED_BY_TAG = {
|
|
9
|
-
"mj-image" => %w[src],
|
|
10
|
-
"mj-font" => %w[name href],
|
|
11
|
-
"mj-include" => %w[path]
|
|
12
|
-
}.freeze
|
|
13
|
-
|
|
14
8
|
def initialize(parser: Parser.new)
|
|
15
9
|
@parser = parser
|
|
16
10
|
end
|
|
17
11
|
|
|
18
12
|
def validate(mjml_or_ast, options = {})
|
|
19
|
-
|
|
13
|
+
options = Options::DEFAULTS.merge(Options.normalize(options))
|
|
14
|
+
parsed = if mjml_or_ast.is_a?(Parser::ParseResult)
|
|
15
|
+
mjml_or_ast
|
|
16
|
+
elsif mjml_or_ast.is_a?(Nokogiri::XML::Node)
|
|
17
|
+
Parser::ParseResult.new(ast: mjml_or_ast, diagnostics: [])
|
|
18
|
+
else
|
|
19
|
+
@parser.parse_result(mjml_or_ast, options)
|
|
20
|
+
end
|
|
21
|
+
root = parsed.ast
|
|
20
22
|
unless root&.tag_name == "mjml"
|
|
21
23
|
return { errors: [error("Root element must be <mjml>", tag_name: root&.tag_name)], warnings: [] }
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
issues =
|
|
26
|
+
issues = parsed.diagnostics.dup
|
|
27
|
+
return classify_issues(issues, options) if options[:validation_level].to_s == "skip"
|
|
25
28
|
issues << error("Missing <mj-body>", tag_name: "mjml") unless root.element_children.any? { |c| c.tag_name == "mj-body" }
|
|
26
29
|
walk(root, issues)
|
|
27
30
|
classify_issues(issues, options)
|
|
28
31
|
rescue Parser::ParseError => e
|
|
29
|
-
{ errors: [error(e.message, line: e.line)], warnings: [] }
|
|
32
|
+
{ errors: [error(e.message, line: e.line, file: e.file)], warnings: [] }
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
private
|
|
@@ -42,23 +45,11 @@ module MjmlRb
|
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
|
|
45
|
-
def parse_ast(mjml, options)
|
|
46
|
-
@parser.parse(
|
|
47
|
-
mjml,
|
|
48
|
-
keep_comments: options.fetch(:keep_comments, false),
|
|
49
|
-
preprocessors: options.fetch(:preprocessors, []),
|
|
50
|
-
ignore_includes: options.fetch(:ignore_includes, false),
|
|
51
|
-
file_path: options.fetch(:file_path, "."),
|
|
52
|
-
actual_path: options.fetch(:actual_path, ".")
|
|
53
|
-
)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
48
|
def walk(node, errors)
|
|
57
49
|
return unless node.element?
|
|
58
50
|
|
|
59
51
|
validate_known_tag(node, errors)
|
|
60
52
|
validate_allowed_children(node, errors)
|
|
61
|
-
validate_required_attributes(node, errors)
|
|
62
53
|
validate_supported_attributes(node, errors)
|
|
63
54
|
validate_attribute_types(node, errors)
|
|
64
55
|
|
|
@@ -94,19 +85,9 @@ module MjmlRb
|
|
|
94
85
|
end
|
|
95
86
|
end
|
|
96
87
|
|
|
97
|
-
def validate_required_attributes(node, errors)
|
|
98
|
-
required = REQUIRED_BY_TAG[node.tag_name] || []
|
|
99
|
-
required.each do |attr|
|
|
100
|
-
next if node.has_attribute?(attr)
|
|
101
|
-
|
|
102
|
-
errors << error("Attribute `#{attr}` is required for <#{node.tag_name}>",
|
|
103
|
-
tag_name: node.tag_name, line: node.line, file: node.file)
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
|
|
107
88
|
def validate_supported_attributes(node, errors)
|
|
108
89
|
allowed_attributes = allowed_attributes_for(node.tag_name)
|
|
109
|
-
return if
|
|
90
|
+
return if node.tag_name == "mjml" || node.parent&.name == "mj-attributes"
|
|
110
91
|
|
|
111
92
|
string_attrs(node).each_key do |attribute_name|
|
|
112
93
|
next if allowed_attributes.key?(attribute_name)
|
|
@@ -218,7 +199,7 @@ module MjmlRb
|
|
|
218
199
|
end
|
|
219
200
|
end
|
|
220
201
|
|
|
221
|
-
INTERNAL_ATTRIBUTES = %w[data-mjml-file data-mjml-ending-tag data-mjml-raw].freeze
|
|
202
|
+
INTERNAL_ATTRIBUTES = %w[data-mjml-file data-mjml-line data-mjml-ending-tag data-mjml-raw].freeze
|
|
222
203
|
|
|
223
204
|
def string_attrs(node)
|
|
224
205
|
result = {}
|
data/lib/mjml-rb/version.rb
CHANGED
data/lib/mjml-rb.rb
CHANGED
|
@@ -16,8 +16,8 @@ module MjmlRb
|
|
|
16
16
|
warn <<~WARNING unless ENV["MJML_RB_NO_WARN"] == "1"
|
|
17
17
|
WARNING: mjml-rb #{VERSION} is EXPERIMENTAL software.
|
|
18
18
|
It is an unofficial Ruby port of MJML, not affiliated with or endorsed by
|
|
19
|
-
the MJML team.
|
|
20
|
-
|
|
19
|
+
the MJML team. It targets MJML #{MJML_COMPATIBILITY_VERSION}; parser, formatter
|
|
20
|
+
and CSS inliner behavior may differ. Use in production at your own risk.
|
|
21
21
|
Set MJML_RB_NO_WARN=1 to suppress this message.
|
|
22
22
|
WARNING
|
|
23
23
|
|
data/mjml-rb.gemspec
CHANGED
|
@@ -13,11 +13,11 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
|
|
14
14
|
spec.homepage = "https://github.com/faraquet/mjml-rb"
|
|
15
15
|
spec.files = Dir.chdir(__dir__) do
|
|
16
|
-
Dir.glob("{bin,lib}/**/*") + ["Gemfile", "LICENSE", "Rakefile", "mjml-rb.gemspec", "README.md"]
|
|
16
|
+
Dir.glob("{bin,lib}/**/*") + Dir.glob("docs/**/*.md") + ["Gemfile", "LICENSE", "THIRD_PARTY_LICENSES.md", "Rakefile", "mjml-rb.gemspec", "README.md", "CHANGELOG.md"]
|
|
17
17
|
end
|
|
18
18
|
spec.bindir = "bin"
|
|
19
19
|
spec.executables = ["mjml"]
|
|
20
20
|
spec.require_paths = ["lib"]
|
|
21
|
-
spec.add_dependency "css_parser", ">= 1.17"
|
|
21
|
+
spec.add_dependency "css_parser", ">= 1.17", "< 4"
|
|
22
22
|
spec.add_dependency "nokogiri", ">= 1.13"
|
|
23
23
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mjml-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Andriichuk
|
|
@@ -16,6 +16,9 @@ dependencies:
|
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '1.17'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '4'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -23,6 +26,9 @@ dependencies:
|
|
|
23
26
|
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
28
|
version: '1.17'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '4'
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: nokogiri
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -45,13 +51,23 @@ executables:
|
|
|
45
51
|
extensions: []
|
|
46
52
|
extra_rdoc_files: []
|
|
47
53
|
files:
|
|
54
|
+
- CHANGELOG.md
|
|
48
55
|
- Gemfile
|
|
49
56
|
- LICENSE
|
|
50
57
|
- README.md
|
|
51
58
|
- Rakefile
|
|
59
|
+
- THIRD_PARTY_LICENSES.md
|
|
52
60
|
- bin/mjml
|
|
61
|
+
- docs/ARCHITECTURE.md
|
|
62
|
+
- docs/MIGRATING_TO_V5.md
|
|
63
|
+
- docs/MJML_V5_SUPPORT_PLAN.md
|
|
64
|
+
- docs/PARITY_AUDIT.md
|
|
65
|
+
- docs/RELEASING.md
|
|
66
|
+
- docs/USAGE.md
|
|
67
|
+
- docs/releases/v0.6.0.md
|
|
53
68
|
- lib/mjml-rb.rb
|
|
54
69
|
- lib/mjml-rb/cli.rb
|
|
70
|
+
- lib/mjml-rb/column_gutter.rb
|
|
55
71
|
- lib/mjml-rb/compiler.rb
|
|
56
72
|
- lib/mjml-rb/component_registry.rb
|
|
57
73
|
- lib/mjml-rb/components/accordion.rb
|
|
@@ -79,7 +95,9 @@ files:
|
|
|
79
95
|
- lib/mjml-rb/components/text.rb
|
|
80
96
|
- lib/mjml-rb/config_file.rb
|
|
81
97
|
- lib/mjml-rb/dependencies.rb
|
|
98
|
+
- lib/mjml-rb/formatter.rb
|
|
82
99
|
- lib/mjml-rb/node_compat.rb
|
|
100
|
+
- lib/mjml-rb/options.rb
|
|
83
101
|
- lib/mjml-rb/parser.rb
|
|
84
102
|
- lib/mjml-rb/railtie.rb
|
|
85
103
|
- lib/mjml-rb/renderer.rb
|