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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/abstract-syntax-tree.md +3 -4
- data/context/headings.md +19 -20
- data/ext/markly/blocks.c +33 -6
- data/lib/markly/node.rb +1 -0
- data/lib/markly/renderer/generic.rb +3 -3
- data/lib/markly/renderer/html.rb +13 -8
- data/lib/markly/version.rb +1 -1
- data/license.md +4 -2
- data/readme.md +20 -8
- data.tar.gz.sig +0 -0
- metadata +7 -5
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76b9702e08b93aa97c2fe8b02d0ac1faea07b8037cf093c48d87b4b7e260806a
|
|
4
|
+
data.tar.gz: b3cad63b1de5e67e2160c72731f28cea94d02fbe999c5b2f2201f3e94b6c84b7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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 (
|
|
300
|
-
|
|
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
|
@@ -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
|
|
29
|
+
@node.each{|child| out(child)}
|
|
30
30
|
elsif arg.is_a?(Array)
|
|
31
|
-
arg.each
|
|
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
|
|
46
|
+
node.each{|child| render(child)}
|
|
47
47
|
else
|
|
48
48
|
send(node.type, node)
|
|
49
49
|
end
|
data/lib/markly/renderer/html.rb
CHANGED
|
@@ -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-
|
|
9
|
+
# Copyright, 2020-2026, by Samuel Williams.
|
|
10
10
|
|
|
11
11
|
require_relative "generic"
|
|
12
12
|
require_relative "headings"
|
|
13
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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], "")
|
data/lib/markly/version.rb
CHANGED
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-
|
|
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
|
[](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
|
-
|
|
14
|
-
|
|
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.
|
|
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.
|
|
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:
|
|
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
|