prosemirror_to_html 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f284982bc72b18c9ef678e23833febc9f5326f7c02fa5fcd0f24d2b3b01a068c
4
- data.tar.gz: 72026340795ebd8a342be9693ebf401f2c37fb75bcdf44c740cec2c351a046e3
3
+ metadata.gz: 32c2b7bb3c4e6605b5be4eeb87d5529b3457400f335a4cb581a2fae039cbd47b
4
+ data.tar.gz: b64c662ea99e41371edf715e830aea49390c35dc546b197b10c98dbc8246632d
5
5
  SHA512:
6
- metadata.gz: 364d04e54e3c17755dca5365798cbb75f72b9b5597d8dda3c513a2a43e9092f90e45764fb06dda0626adc6b78bcc8af8962bf8c54bec74956716e22fff97e35c
7
- data.tar.gz: 91a7c87d2527b9cf4350722e1f4d454405b7e88b1e8a3ab04524b60d1c76c19d89b527105a7c704c3cfbcdeef938a9a6245a13ffdadc29d098ddba260730b067
6
+ metadata.gz: 771cebd6d454024922deb4c937b26ae624c2b5ee754ab74e74c24d6e8197ee8cfd8531ae75cff8fa96273e2f2f8f43d4fe99e24301a1b464649660f58c749ef9
7
+ data.tar.gz: 8de0c80c0c76f7ca9b87d641796b77d98982d915876663cea5d204e47e4b759026ead473c64c9dc572162661e8300c1c3dc291e73fe98753f186c678d81fb4d9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [0.3.0] - 2026-02-18
2
+
3
+ ### Changed
4
+
5
+ - Remove dependency to `OpenStruct`
6
+
7
+ ### Fixed
8
+
9
+ - Fix mark grouping: marks shared across adjacent text nodes (e.g. a `link` spanning multiple runs) are now correctly rendered as a single wrapping tag instead of being reopened for each node
10
+
11
+ ## [0.2.1] - 2025-11-05
12
+
13
+ - Escape attributes values [CVE-2025-64501]
14
+
1
15
  ## [0.2.0] - 2023-07-03
2
16
 
3
17
  Hans Lemuet (@Spone) is the new maintainer. The fork is now hosted at https://github.com/etaminstudio/prosemirror_to_html
data/Gemfile.lock CHANGED
@@ -1,43 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prosemirror_to_html (0.2.0)
4
+ prosemirror_to_html (0.3.0)
5
5
  nokogiri
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- diff-lcs (1.5.0)
11
- mini_portile2 (2.8.2)
12
- nokogiri (1.15.2)
10
+ diff-lcs (1.6.2)
11
+ mini_portile2 (2.8.9)
12
+ nokogiri (1.19.1)
13
13
  mini_portile2 (~> 2.8.2)
14
14
  racc (~> 1.4)
15
- racc (1.7.1)
16
- rake (13.0.6)
17
- rspec (3.12.0)
18
- rspec-core (~> 3.12.0)
19
- rspec-expectations (~> 3.12.0)
20
- rspec-mocks (~> 3.12.0)
21
- rspec-core (3.12.2)
22
- rspec-support (~> 3.12.0)
23
- rspec-expectations (3.12.3)
15
+ racc (1.8.1)
16
+ rake (13.3.1)
17
+ rspec (3.13.2)
18
+ rspec-core (~> 3.13.0)
19
+ rspec-expectations (~> 3.13.0)
20
+ rspec-mocks (~> 3.13.0)
21
+ rspec-core (3.13.6)
22
+ rspec-support (~> 3.13.0)
23
+ rspec-expectations (3.13.5)
24
24
  diff-lcs (>= 1.2.0, < 2.0)
25
- rspec-support (~> 3.12.0)
26
- rspec-mocks (3.12.5)
25
+ rspec-support (~> 3.13.0)
26
+ rspec-mocks (3.13.7)
27
27
  diff-lcs (>= 1.2.0, < 2.0)
28
- rspec-support (~> 3.12.0)
29
- rspec-support (3.12.1)
30
- yard (0.9.34)
28
+ rspec-support (~> 3.13.0)
29
+ rspec-support (3.13.7)
30
+ yard (0.9.38)
31
31
 
32
32
  PLATFORMS
33
33
  ruby
34
34
 
35
35
  DEPENDENCIES
36
- bundler (~> 2.1.4)
36
+ bundler (~> 2.3)
37
37
  prosemirror_to_html!
38
38
  rake (~> 13.0)
39
39
  rspec (~> 3.0)
40
40
  yard
41
41
 
42
42
  BUNDLED WITH
43
- 2.1.4
43
+ 2.7.2
@@ -5,18 +5,10 @@ module ProsemirrorToHtml
5
5
  @tag_name = 'a'
6
6
 
7
7
  def tag
8
- attrs = {}
9
-
10
- attrs['href'] = @mark.attrs.href
11
-
12
- attrs['target'] = @mark.attrs.target if @mark.attrs.target
13
- attrs['title'] = @mark.attrs.title if @mark.attrs.title
14
- attrs['rel'] = @mark.attrs.rel if @mark.attrs.rel
15
-
16
8
  [
17
9
  {
18
10
  tag: self.class.tag_name,
19
- attrs: attrs
11
+ attrs: @mark[:attrs]
20
12
  }
21
13
  ]
22
14
  end
@@ -13,7 +13,7 @@ module ProsemirrorToHtml
13
13
  end
14
14
 
15
15
  def matching
16
- return @mark.type == self.class.mark_type if @mark.type
16
+ return @mark[:type] == self.class.mark_type if @mark[:type]
17
17
 
18
18
  false
19
19
  end
@@ -6,7 +6,7 @@ module ProsemirrorToHtml
6
6
  def tag
7
7
  [
8
8
  {
9
- tag: "h#{@node.attrs.level}",
9
+ tag: "h#{@node[:attrs][:level]}",
10
10
  attrs: tag_attrs
11
11
  }
12
12
  ]
@@ -15,7 +15,7 @@ module ProsemirrorToHtml
15
15
  private
16
16
 
17
17
  def tag_attrs
18
- attrs_hash = @node.attrs.to_h
18
+ attrs_hash = @node[:attrs].to_h
19
19
  attrs_hash.slice(*attrs_hash.keys - %i[level])
20
20
  end
21
21
  end
@@ -8,7 +8,7 @@ module ProsemirrorToHtml
8
8
  [
9
9
  {
10
10
  tag: self.class.tag_name,
11
- attrs: @node.attrs
11
+ attrs: @node[:attrs]
12
12
  }
13
13
  ]
14
14
  end
@@ -13,7 +13,7 @@ module ProsemirrorToHtml
13
13
  end
14
14
 
15
15
  def matching
16
- return underscore(@node.type) == self.class.node_type if @node.type
16
+ return underscore(@node[:type]) == self.class.node_type if @node[:type]
17
17
 
18
18
  false
19
19
  end
@@ -8,7 +8,7 @@ module ProsemirrorToHtml
8
8
  [
9
9
  {
10
10
  tag: self.class.tag_name,
11
- attrs: @node.attrs
11
+ attrs: @node[:attrs]
12
12
  }
13
13
  ]
14
14
  end
@@ -8,7 +8,7 @@ module ProsemirrorToHtml
8
8
  [
9
9
  {
10
10
  tag: self.class.tag_name,
11
- attrs: @node.attrs
11
+ attrs: @node[:attrs]
12
12
  }
13
13
  ]
14
14
  end
@@ -8,7 +8,7 @@ module ProsemirrorToHtml
8
8
  [
9
9
  {
10
10
  tag: self.class.tag_name,
11
- attrs: @node.attrs
11
+ attrs: @node[:attrs]
12
12
  }
13
13
  ]
14
14
  end
@@ -1,3 +1,3 @@
1
1
  module ProsemirrorToHtml
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -25,7 +25,6 @@ require "prosemirror_to_html/nodes/table_header"
25
25
  require "prosemirror_to_html/nodes/table_row"
26
26
  require 'nokogiri'
27
27
  require 'json'
28
- require "ostruct"
29
28
 
30
29
  module ProsemirrorToHtml
31
30
  class Error < StandardError; end
@@ -82,14 +81,14 @@ module ProsemirrorToHtml
82
81
  else raise Error
83
82
  end
84
83
 
85
- @document = JSON.parse(json, object_class: OpenStruct)
84
+ @document = JSON.parse(json, symbolize_names: true)
86
85
 
87
86
  html = ''
88
87
 
89
- content = @document.content.is_a?(Array) ? @document.content : []
88
+ content = @document[:content].is_a?(Array) ? @document[:content] : []
90
89
 
91
90
  content.each_with_index do |node, index|
92
- prev_node = content[index - 1]
91
+ prev_node = index > 0 ? content[index - 1] : nil
93
92
  next_node = content[index + 1]
94
93
 
95
94
  html << render_node(node, prev_node, next_node)
@@ -148,14 +147,12 @@ module ProsemirrorToHtml
148
147
  html = ''
149
148
  render_klass = nil
150
149
 
151
- if node&.marks
152
- node.marks.each do |mark|
153
- @marks.each do |klass|
154
- render_klass = klass.new(mark)
150
+ node[:marks]&.each do |mark|
151
+ @marks.each do |klass|
152
+ render_klass = klass.new(mark)
155
153
 
156
- if render_klass.matching && mark_should_open(mark, prev_node)
157
- html << render_opening_tag(render_klass.tag)
158
- end
154
+ if render_klass.matching && mark_should_open(mark, prev_node)
155
+ html << render_opening_tag(render_klass.tag)
159
156
  end
160
157
  end
161
158
  end
@@ -169,17 +166,16 @@ module ProsemirrorToHtml
169
166
  end
170
167
  end
171
168
 
172
- if node&.content
173
- node.content.each_with_index do |nested_node, index|
174
- prev_nested_node = node.content[index - 1]
175
- next_nested_node = node.content[index + 1]
169
+ if node[:content]
170
+ node[:content].each_with_index do |nested_node, index|
171
+ prev_nested_node = index > 0 ? node[:content][index - 1] : nil
172
+ next_nested_node = node[:content][index + 1]
176
173
 
177
174
  html << render_node(nested_node, prev_nested_node, next_nested_node)
178
- prev_node = nested_node
179
175
  end
180
- elsif node&.text
181
- html << CGI.escapeHTML(node.text)
182
- elsif text = render_klass.text
176
+ elsif node[:text]
177
+ html << CGI.escapeHTML(node[:text])
178
+ elsif (text = render_klass.text)
183
179
  html << text
184
180
  end
185
181
 
@@ -195,14 +191,12 @@ module ProsemirrorToHtml
195
191
  end
196
192
  end
197
193
 
198
- if node&.marks
199
- node.marks.reverse.each do |mark|
200
- @marks.each do |klass|
201
- render_klass = klass.new(mark)
194
+ node[:marks]&.reverse&.each do |mark|
195
+ @marks.each do |klass|
196
+ render_klass = klass.new(mark)
202
197
 
203
- if render_klass.matching && mark_should_close(mark, next_node)
204
- html << render_closing_tag(render_klass.tag)
205
- end
198
+ if render_klass.matching && mark_should_close(mark, next_node)
199
+ html << render_closing_tag(render_klass.tag)
206
200
  end
207
201
  end
208
202
  end
@@ -220,14 +214,9 @@ module ProsemirrorToHtml
220
214
 
221
215
  def node_has_mark(node, mark)
222
216
  return true unless node
223
- return true if node.respond_to?(:marks)
224
217
 
225
- # Other node has same mark
226
- node.marks&.each do |other_mark|
227
- if mark == other_mark
228
- return false
229
- end
230
- end
218
+ # Don't open/close if the adjacent node shares the same mark
219
+ return false if node[:marks]&.map(&:to_json)&.include?(mark.to_json)
231
220
 
232
221
  true
233
222
  end
@@ -241,22 +230,20 @@ module ProsemirrorToHtml
241
230
  if tag.is_a? String
242
231
  "<#{tag}>"
243
232
  else
244
- tag = OpenStruct.new(tag) unless tag.is_a?(OpenStruct)
245
-
246
233
  attrs = ''
247
- if tag&.attrs
248
- tag.attrs.each_pair do |attr, value|
249
- attrs << " #{attr}=\"#{value}\""
250
- end
234
+ tag[:attrs]&.each_pair do |attr, value|
235
+ escaped_value = CGI.escapeHTML(value.to_s)
236
+ attrs << " #{attr}=\"#{escaped_value}\""
251
237
  end
252
238
 
253
- "<#{tag.tag}#{attrs}>"
239
+ "<#{tag[:tag]}#{attrs}>"
254
240
  end
255
241
  end.join
256
242
  end
257
243
 
258
244
  def render_closing_tag(tags)
259
245
  tags = array_wrap(tags).reverse
246
+ p ["render_closing_tag", tags]
260
247
 
261
248
  return nil if tags.empty?
262
249
 
@@ -264,9 +251,7 @@ module ProsemirrorToHtml
264
251
  if tag.is_a? String
265
252
  "</#{tag}>"
266
253
  else
267
- tag = OpenStruct.new(tag) unless tag.is_a?(OpenStruct)
268
-
269
- "</#{tag.tag}>"
254
+ "</#{tag[:tag]}>"
270
255
  end
271
256
  end.join
272
257
  end
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
38
  spec.require_paths = ["lib"]
39
39
 
40
- spec.add_development_dependency "bundler", "~> 2.1.4"
40
+ spec.add_development_dependency "bundler", "~> 2.3"
41
41
  spec.add_development_dependency "rake", "~> 13.0"
42
42
  spec.add_development_dependency "rspec", "~> 3.0"
43
43
  spec.add_development_dependency "yard"
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prosemirror_to_html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hans Lemuet
8
8
  - Brian Kimball
9
- autorequire:
10
9
  bindir: exe
11
10
  cert_chain: []
12
- date: 2023-07-03 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -17,14 +16,14 @@ dependencies:
17
16
  requirements:
18
17
  - - "~>"
19
18
  - !ruby/object:Gem::Version
20
- version: 2.1.4
19
+ version: '2.3'
21
20
  type: :development
22
21
  prerelease: false
23
22
  version_requirements: !ruby/object:Gem::Requirement
24
23
  requirements:
25
24
  - - "~>"
26
25
  - !ruby/object:Gem::Version
27
- version: 2.1.4
26
+ version: '2.3'
28
27
  - !ruby/object:Gem::Dependency
29
28
  name: rake
30
29
  requirement: !ruby/object:Gem::Requirement
@@ -135,7 +134,6 @@ homepage: https://github.com/etaminstudio/prosemirror_to_html
135
134
  licenses:
136
135
  - MIT
137
136
  metadata: {}
138
- post_install_message:
139
137
  rdoc_options: []
140
138
  require_paths:
141
139
  - lib
@@ -150,8 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
148
  - !ruby/object:Gem::Version
151
149
  version: '0'
152
150
  requirements: []
153
- rubygems_version: 3.3.26
154
- signing_key:
151
+ rubygems_version: 4.0.3
155
152
  specification_version: 4
156
153
  summary: Takes ProseMirror compatible JSON and outputs HTML.
157
154
  test_files: []