markly 0.15.1 → 0.15.3

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: 712a0a7ad856598eb83b20c370e7613896596af5c76cc2379a368382802f09db
4
- data.tar.gz: f775598d6fc6e4d5e340bf68518816d3bd23bc44facd209fcd59bd4f0d429639
3
+ metadata.gz: 76b9702e08b93aa97c2fe8b02d0ac1faea07b8037cf093c48d87b4b7e260806a
4
+ data.tar.gz: b3cad63b1de5e67e2160c72731f28cea94d02fbe999c5b2f2201f3e94b6c84b7
5
5
  SHA512:
6
- metadata.gz: f13cbaaba186b5716efb05567721ea024633f0c353f7296721406dd7d4f7918625e5518ae4836371a784808ae99de8d4831bf938df6595ed26da462398c6e39f
7
- data.tar.gz: a92d4ee382baaf2bea98defccfd318142f0fdccf42ff5fca5293c17bf611e432d21e178f3d69a272f0c021309d3725454e93ea401d7473495ff4620490071d5d
6
+ metadata.gz: 701981fe8e9c6a229cc93042a40b4600e9d627903dd5f50e80089e2766c506ceb780c9feb3cb0ca3cdb1621be0e58db5cff0795925c8b42324d4b763312abaf0
7
+ data.tar.gz: 5500f4778efd6753dd6ffc9a5717c372c4a0d422db38695466bb2ddd9bb16a3a1ba138c34382f9ed3278c4a69ff75a29172ce581ce0138a20e4ab3b6c9b2be8a
checksums.yaml.gz.sig CHANGED
Binary file
@@ -39,7 +39,7 @@ You can use `walk` or `each` to iterate over nodes:
39
39
  <!-- end list -->
40
40
 
41
41
  ``` ruby
42
- require 'markly'
42
+ require "markly"
43
43
 
44
44
  document = Markly.parse("# The site\n\n [GitHub](https://www.github.com)")
45
45
 
@@ -80,11 +80,10 @@ class MyHtmlRenderer < Markly::Renderer::HTML
80
80
  super
81
81
  @header_id = 1
82
82
  end
83
-
83
+
84
84
  def header(node)
85
85
  block do
86
- out("<h", node.header_level, " id=\"", @header_id, "\">",
87
- :children, "</h", node.header_level, ">")
86
+ out("<h", node.header_level, " id=\"", @header_id, "\">", :children, "</h", node.header_level, ">")
88
87
  @header_id += 1
89
88
  end
90
89
  end
data/context/headings.md CHANGED
@@ -38,7 +38,7 @@ document = Markly.parse(markdown)
38
38
  headings = Markly::Renderer::Headings.extract(document, min_level: 2, max_level: 3)
39
39
 
40
40
  headings.each do |heading|
41
- puts "#{heading.level}: #{heading.text} (#{heading.anchor})"
41
+ puts "#{heading.level}: #{heading.text} (#{heading.anchor})"
42
42
  end
43
43
 
44
44
  # Output:
@@ -90,25 +90,24 @@ Subclass `Headings` to implement alternative ID generation strategies:
90
90
 
91
91
  ``` ruby
92
92
  class HierarchicalHeadings < Markly::Renderer::Headings
93
- def initialize
94
- super
95
- @parent_context = []
96
- end
97
-
98
- def anchor_for(node)
99
- base = base_anchor_for(node)
100
-
101
- # Custom logic: could incorporate parent heading context
102
- # to generate IDs like "kubernetes-deployment" instead of "deployment-2"
103
-
104
- if @ids.key?(base)
105
- @ids[base] += 1
106
- "#{base}-#{@ids[base]}"
107
- else
108
- @ids[base] = 1
109
- base
110
- end
111
- end
93
+ def initialize
94
+ super
95
+ @parent_context = []
96
+ end
97
+
98
+ def anchor_for(node)
99
+ base = base_anchor_for(node)
100
+
101
+ # Custom logic: could incorporate parent heading context to generate IDs like "kubernetes-deployment" instead of "deployment-2"
102
+
103
+ if @ids.key?(base)
104
+ @ids[base] += 1
105
+ "#{base}-#{@ids[base]}"
106
+ else
107
+ @ids[base] = 1
108
+ base
109
+ end
110
+ end
112
111
  end
113
112
 
114
113
  renderer = Markly::Renderer::HTML.new(headings: HierarchicalHeadings.new)
data/ext/markly/blocks.c CHANGED
@@ -72,6 +72,34 @@ static CMARK_INLINE bool S_is_space_or_tab(char c) {
72
72
  return (c == ' ' || c == '\t');
73
73
  }
74
74
 
75
+ // Returns true if block is being finalized on the same line it ends.
76
+ // This happens for:
77
+ // - Document node (special case)
78
+ // - Fenced code blocks (end on the closing fence line)
79
+ // - Setext headings (end on the underline)
80
+ // - HTML blocks types 1-5 per CommonMark spec §4.6 (end on the line
81
+ // containing the closing marker)
82
+ // - Any block finalized on the same line it started (e.g., single-line blocks)
83
+ static CMARK_INLINE bool S_ends_on_current_line(cmark_parser *parser, cmark_node *b) {
84
+ return S_type(b) == CMARK_NODE_DOCUMENT ||
85
+ (S_type(b) == CMARK_NODE_CODE_BLOCK && b->as.code.fenced) ||
86
+ (S_type(b) == CMARK_NODE_HEADING && b->as.heading.setext) ||
87
+ // HTML block types per CommonMark spec §4.6:
88
+ // 1: <script>, <pre>, <style>, <textarea> (ends at </tag>)
89
+ // 2: <!-- (ends at -->)
90
+ // 3: <? (ends at ?>)
91
+ // 4: <! + letter (ends at >)
92
+ // 5: <![CDATA[ (ends at ]]>)
93
+ // All five end on the line containing their closing marker,
94
+ // similar to fenced code blocks.
95
+ // Types 6-7 end at a blank line, so their last content line is
96
+ // the previous line and they should NOT match here.
97
+ (S_type(b) == CMARK_NODE_HTML_BLOCK && b->as.html_block_type >= 1 &&
98
+ b->as.html_block_type <= 5) ||
99
+ // Single-line blocks: finalized on same line they started
100
+ b->start_line == parser->line_number;
101
+ }
102
+
75
103
  static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
76
104
  size_t len, bool eof);
77
105
 
@@ -288,17 +316,15 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
288
316
  bool has_content;
289
317
 
290
318
  parent = b->parent;
291
- assert(b->flags &
292
- CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks
319
+ assert(b->flags & CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks
293
320
  b->flags &= ~CMARK_NODE__OPEN;
294
321
 
295
322
  if (parser->curline.size == 0) {
296
- // end of input - line number has not been incremented
323
+ // end of input - line number has not been incremented:
297
324
  b->end_line = parser->line_number;
298
325
  b->end_column = parser->last_line_length;
299
- } else if (S_type(b) == CMARK_NODE_DOCUMENT ||
300
- (S_type(b) == CMARK_NODE_CODE_BLOCK && b->as.code.fenced) ||
301
- (S_type(b) == CMARK_NODE_HEADING && b->as.heading.setext)) {
326
+ } else if (S_ends_on_current_line(parser, b)) {
327
+ // Block ends on current line (line_number already incremented):
302
328
  b->end_line = parser->line_number;
303
329
  b->end_column = parser->curline.size;
304
330
  if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\n')
@@ -306,6 +332,7 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
306
332
  if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\r')
307
333
  b->end_column -= 1;
308
334
  } else {
335
+ // Block ended on a previous line:
309
336
  b->end_line = parser->line_number - 1;
310
337
  b->end_column = parser->last_line_length;
311
338
  }
data/lib/markly/node.rb CHANGED
@@ -6,6 +6,7 @@
6
6
  # Copyright, 2017, by Goro Fuji.
7
7
  # Copyright, 2018, by Jerry van Leeuwen.
8
8
  # Copyright, 2020-2025, by Samuel Williams.
9
+ # Copyright, 2025, by Olle Jonsson.
9
10
 
10
11
  require_relative "node/inspect"
11
12
 
@@ -26,9 +26,9 @@ module Markly
26
26
  def out(*args)
27
27
  args.each do |arg|
28
28
  if arg == :children
29
- @node.each {|child| out(child)}
29
+ @node.each{|child| out(child)}
30
30
  elsif arg.is_a?(Array)
31
- arg.each {|x| render(x)}
31
+ arg.each{|x| render(x)}
32
32
  elsif arg.is_a?(Node)
33
33
  render(arg)
34
34
  else
@@ -43,7 +43,7 @@ module Markly
43
43
  document(node)
44
44
  @stream.string
45
45
  elsif @in_plain && node.type != :text && node.type != :softbreak
46
- node.each {|child| render(child)}
46
+ node.each{|child| render(child)}
47
47
  else
48
48
  send(node.type, node)
49
49
  end
@@ -6,11 +6,17 @@
6
6
  # Copyright, 2017, by Yuki Izumi.
7
7
  # Copyright, 2017-2019, by Ashe Connor.
8
8
  # Copyright, 2018, by Michael Camilleri.
9
- # Copyright, 2020-2025, by Samuel Williams.
9
+ # Copyright, 2020-2026, by Samuel Williams.
10
10
 
11
11
  require_relative "generic"
12
12
  require_relative "headings"
13
- require "cgi"
13
+
14
+ require "cgi/escape"
15
+
16
+ # Compatibility for older Ruby versions where escape_html alias doesn't exist:
17
+ unless CGI.respond_to?(:escape_html)
18
+ require "cgi"
19
+ end
14
20
 
15
21
  module Markly
16
22
  module Renderer
@@ -63,8 +69,7 @@ module Markly
63
69
  out("<section#{id_for(node)}>")
64
70
  end
65
71
 
66
- out("<h", node.header_level, "#{source_position(node)}>", :children,
67
- "</h", node.header_level, ">")
72
+ out("<h", node.header_level, "#{source_position(node)}>", :children, "</h", node.header_level, ">")
68
73
  end
69
74
  end
70
75
 
@@ -256,10 +261,10 @@ module Markly
256
261
  end
257
262
 
258
263
  TABLE_CELL_ALIGNMENT = {
259
- left: ' align="left"',
260
- right: ' align="right"',
261
- center: ' align="center"'
262
- }.freeze
264
+ left: ' align="left"',
265
+ right: ' align="right"',
266
+ center: ' align="center"'
267
+ }.freeze
263
268
 
264
269
  def table_cell(node)
265
270
  align = TABLE_CELL_ALIGNMENT.fetch(@alignments[@column_index], "")
@@ -7,5 +7,5 @@
7
7
  # Copyright, 2020-2025, by Samuel Williams.
8
8
 
9
9
  module Markly
10
- VERSION = "0.15.1"
10
+ VERSION = "0.15.3"
11
11
  end
data/license.md CHANGED
@@ -17,9 +17,11 @@ Copyright, 2018, by Akira Matsuda.
17
17
  Copyright, 2018, by Danny Iachini.
18
18
  Copyright, 2019-2020, by Tomoya Chiba.
19
19
  Copyright, 2019, by Brett Walker.
20
- Copyright, 2020, by Olle Jonsson.
21
- Copyright, 2020-2025, by Samuel Williams.
20
+ Copyright, 2020-2025, by Olle Jonsson.
21
+ Copyright, 2020-2026, by Samuel Williams.
22
22
  Copyright, 2024, by Ross Kaffenberger.
23
+ Copyright, 2025, by Henrik Nyh.
24
+ Copyright, 2025-2026, by Peter H. Boling.
23
25
 
24
26
  Permission is hereby granted, free of charge, to any person obtaining a copy
25
27
  of this software and associated documentation files (the "Software"), to deal
data/readme.md CHANGED
@@ -1,18 +1,14 @@
1
1
  # Markly
2
2
 
3
- A parser and abstract syntax tree for Markdown documents (CommonMark compatible) in Ruby. Originally forked from
4
- [CommonMarker](https://github.com/gjtorikian/commonmarker). It also includes extensions to the CommonMark spec as
5
- documented in the [GitHub Flavored Markdown spec](http://github.github.com/gfm/), such as support for tables,
6
- strikethroughs, and autolinking.
3
+ A parser and abstract syntax tree for Markdown documents (CommonMark compatible) in Ruby. Originally forked from [CommonMarker](https://github.com/gjtorikian/commonmarker). It also includes extensions to the CommonMark spec as documented in the [GitHub Flavored Markdown spec](http://github.github.com/gfm/), such as support for tables, strikethroughs, and autolinking.
7
4
 
8
5
  [![Development Status](https://github.com/ioquatix/markly/workflows/Test/badge.svg)](https://github.com/ioquatix/markly/actions?workflow=Test)
9
6
 
10
7
  ## Motivation
11
8
 
12
- This code base was originally forked from [Commonmarker](https://github.com/gjtorikian/commonmarker) before they
13
- switched from `cmark-gfm` (C) to `comrak` (Rust). The original implementation provided access to the abstract syntax
14
- tree (AST), which is useful for building tools on top of Markdown. The Rust implementation does not provide this
15
- functionality, and so this fork was created to continue to provide these (and more) features.
9
+ This code base was originally forked from [Commonmarker](https://github.com/gjtorikian/commonmarker) before they switched from `cmark-gfm` (C) to `comrak` (Rust). The original implementation provided access to the abstract syntax tree (AST), which is useful for building tools on top of Markdown. The Rust implementation did not provide this functionality, and so this fork was created to continue to provide these (and more) features.
10
+
11
+ It should be noted that `commonmarker` re-introduced AST access, but the original C implementation in this fork is [3-4x faster at processing Markdown into HTML](https://github.com/gjtorikian/commonmarker?tab=readme-ov-file#benchmarks) and has a more advanced HTML generation and AST processing features.
16
12
 
17
13
  ## Usage
18
14
 
@@ -50,6 +46,22 @@ We welcome contributions to this project.
50
46
  4. Push to the branch (`git push origin my-new-feature`).
51
47
  5. Create new Pull Request.
52
48
 
49
+ ### Running Tests
50
+
51
+ To run the test suite:
52
+
53
+ ``` shell
54
+ bundle exec sus
55
+ ```
56
+
57
+ ### Making Releases
58
+
59
+ To make a new release:
60
+
61
+ ``` shell
62
+ bundle exec bake gem:release:patch # or minor or major
63
+ ```
64
+
53
65
  ### Developer Certificate of Origin
54
66
 
55
67
  In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.1
4
+ version: 0.15.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
8
- - Yuki Izumi
9
8
  - Samuel Williams
9
+ - Yuki Izumi
10
10
  - John MacFarlane
11
11
  - Ashe Connor
12
12
  - Nick Wellnhofer
@@ -14,13 +14,15 @@ authors:
14
14
  - Andrew Anderson
15
15
  - Ben Woosley
16
16
  - Goro Fuji
17
+ - Olle Jonsson
18
+ - Peter H. Boling
17
19
  - Tomoya Chiba
18
20
  - Akira Matsuda
19
21
  - Danny Iachini
22
+ - Henrik Nyh
20
23
  - Jerry van Leeuwen
21
24
  - Michael Camilleri
22
25
  - Mu-An Chiou
23
- - Olle Jonsson
24
26
  - Roberto Hidalgo
25
27
  - Ross Kaffenberger
26
28
  - Vitaliy Klachkov
@@ -162,14 +164,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
162
164
  requirements:
163
165
  - - ">="
164
166
  - !ruby/object:Gem::Version
165
- version: '3.2'
167
+ version: '3.3'
166
168
  required_rubygems_version: !ruby/object:Gem::Requirement
167
169
  requirements:
168
170
  - - ">="
169
171
  - !ruby/object:Gem::Version
170
172
  version: '0'
171
173
  requirements: []
172
- rubygems_version: 3.6.9
174
+ rubygems_version: 4.0.6
173
175
  specification_version: 4
174
176
  summary: CommonMark parser and renderer. Written in C, wrapped in Ruby.
175
177
  test_files: []
metadata.gz.sig CHANGED
Binary file