red_quilt 0.6.1

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +109 -0
  4. data/.rubocop_todo.yml +7 -0
  5. data/CHANGELOG.md +57 -0
  6. data/README.md +284 -0
  7. data/Rakefile +8 -0
  8. data/ast-spec.md +1227 -0
  9. data/docs/architecture.md +81 -0
  10. data/docs/arena-usage.md +363 -0
  11. data/docs/commonmark-conformance.md +241 -0
  12. data/exe/redquilt +7 -0
  13. data/lib/red_quilt/arena.rb +366 -0
  14. data/lib/red_quilt/block_parser.rb +724 -0
  15. data/lib/red_quilt/blockquote.rb +151 -0
  16. data/lib/red_quilt/cli.rb +182 -0
  17. data/lib/red_quilt/diagnostic.rb +47 -0
  18. data/lib/red_quilt/document.rb +126 -0
  19. data/lib/red_quilt/extended_autolink_pass.rb +185 -0
  20. data/lib/red_quilt/footnote_definition.rb +147 -0
  21. data/lib/red_quilt/footnote_pass.rb +39 -0
  22. data/lib/red_quilt/footnote_registry.rb +68 -0
  23. data/lib/red_quilt/indentation.rb +73 -0
  24. data/lib/red_quilt/inline/builder.rb +674 -0
  25. data/lib/red_quilt/inline/flanking.rb +120 -0
  26. data/lib/red_quilt/inline/html_entities.rb +2180 -0
  27. data/lib/red_quilt/inline/lexer.rb +280 -0
  28. data/lib/red_quilt/inline/link_scanner.rb +315 -0
  29. data/lib/red_quilt/inline/token_kind.rb +39 -0
  30. data/lib/red_quilt/inline/tokens.rb +73 -0
  31. data/lib/red_quilt/inline.rb +34 -0
  32. data/lib/red_quilt/inline_pass.rb +53 -0
  33. data/lib/red_quilt/line.rb +14 -0
  34. data/lib/red_quilt/lint_pass.rb +71 -0
  35. data/lib/red_quilt/list.rb +317 -0
  36. data/lib/red_quilt/node_ref.rb +114 -0
  37. data/lib/red_quilt/node_type.rb +66 -0
  38. data/lib/red_quilt/plain_text.rb +46 -0
  39. data/lib/red_quilt/reference_definition.rb +309 -0
  40. data/lib/red_quilt/renderer/html.rb +279 -0
  41. data/lib/red_quilt/renderer/mdast.rb +152 -0
  42. data/lib/red_quilt/source_map.rb +29 -0
  43. data/lib/red_quilt/source_span.rb +26 -0
  44. data/lib/red_quilt/theme.rb +28 -0
  45. data/lib/red_quilt/themes/default.css +87 -0
  46. data/lib/red_quilt/version.rb +5 -0
  47. data/lib/red_quilt.rb +86 -0
  48. data/mise.toml +2 -0
  49. data/sig/red_quilt.rbs +45 -0
  50. metadata +91 -0
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedQuilt
4
+ module Renderer
5
+ # Builds an MDAST-compatible Hash from the document arena.
6
+ #
7
+ # MDAST (https://github.com/syntax-tree/mdast) is the unified.js AST
8
+ # format for Markdown; emitting it lets external tooling (linters,
9
+ # editor plugins) consume red_quilt output without bespoke adapters.
10
+ class Mdast
11
+ MDAST_TYPE_NAMES = {
12
+ document: "root",
13
+ paragraph: "paragraph",
14
+ heading: "heading",
15
+ thematic_break: "thematicBreak",
16
+ blockquote: "blockquote",
17
+ list: "list",
18
+ list_item: "listItem",
19
+ code_block: "code",
20
+ html_block: "html",
21
+ table: "table",
22
+ table_row: "tableRow",
23
+ table_cell: "tableCell",
24
+ text: "text",
25
+ softbreak: "break",
26
+ hardbreak: "break",
27
+ emphasis: "emphasis",
28
+ strong: "strong",
29
+ code_span: "inlineCode",
30
+ link: "link",
31
+ image: "image",
32
+ html_inline: "html",
33
+ strikethrough: "delete",
34
+ footnote_reference: "footnoteReference",
35
+ footnote_definition: "footnoteDefinition",
36
+ }.freeze
37
+
38
+ def initialize(document)
39
+ @document = document
40
+ @arena = document.arena
41
+ end
42
+
43
+ def render
44
+ node(@document.root_id)
45
+ end
46
+
47
+ private
48
+
49
+ def node(node_id, parent_spread: false)
50
+ type_int = @arena.type(node_id)
51
+ type_sym = NodeType.name_for(type_int)
52
+
53
+ result = { "type" => mdast_type_name(type_sym) }
54
+
55
+ span = @arena.source_span(node_id)
56
+ result["position"] = position(span) if span
57
+
58
+ case type_int
59
+ when NodeType::HEADING
60
+ result["depth"] = @arena.int1(node_id)
61
+ result["children"] = children(node_id)
62
+ when NodeType::LIST
63
+ result["ordered"] = @arena.int1(node_id) == 1
64
+ tight = @arena.int3(node_id) == 1
65
+ result["start"] = @arena.int2(node_id) if result["ordered"]
66
+ result["spread"] = !tight
67
+ result["children"] = children(node_id, parent_spread: !tight)
68
+ when NodeType::LIST_ITEM
69
+ result["spread"] = parent_spread
70
+ result["children"] = children(node_id)
71
+ when NodeType::CODE_BLOCK
72
+ info = @arena.str2(node_id)
73
+ lang = info && !info.empty? ? info.split.first : nil
74
+ result["lang"] = lang
75
+ result["value"] = @arena.text(node_id).to_s
76
+ when NodeType::TEXT
77
+ result["value"] = @arena.text(node_id).to_s
78
+ when NodeType::SOFTBREAK
79
+ result["type"] = "text"
80
+ result["value"] = "\n"
81
+ when NodeType::CODE_SPAN
82
+ result["value"] = @arena.text(node_id).to_s
83
+ when NodeType::LINK
84
+ result["url"] = @arena.str1(node_id).to_s
85
+ title = @arena.str2(node_id)
86
+ result["title"] = title && !title.empty? ? title : nil
87
+ result["children"] = children(node_id)
88
+ when NodeType::IMAGE
89
+ result["url"] = @arena.str1(node_id).to_s
90
+ title = @arena.str2(node_id)
91
+ result["title"] = title && !title.empty? ? title : nil
92
+ result["alt"] = NodeRef.new(@document, node_id).text.to_s
93
+ when NodeType::FOOTNOTE_REFERENCE
94
+ label = @arena.str1(node_id).to_s
95
+ result["identifier"] = label
96
+ result["label"] = label
97
+ when NodeType::FOOTNOTE_DEFINITION
98
+ label = @arena.str1(node_id).to_s
99
+ result["identifier"] = label
100
+ result["label"] = label
101
+ result["children"] = children(node_id)
102
+ when NodeType::HTML_BLOCK, NodeType::HTML_INLINE
103
+ result["value"] = NodeRef.new(@document, node_id).text.to_s
104
+ when NodeType::TABLE
105
+ result["align"] = []
106
+ result["children"] = children(node_id)
107
+ when NodeType::DOCUMENT, NodeType::PARAGRAPH, NodeType::BLOCKQUOTE,
108
+ NodeType::TABLE_ROW, NodeType::TABLE_CELL,
109
+ NodeType::EMPHASIS, NodeType::STRONG, NodeType::STRIKETHROUGH
110
+ result["children"] = children(node_id)
111
+ end
112
+
113
+ result
114
+ end
115
+
116
+ def children(node_id, parent_spread: false)
117
+ result = []
118
+ @arena.child_ids(node_id).each do |child_id|
119
+ # mdast has no footnotes-section wrapper: footnote definitions are
120
+ # plain root-level nodes, so splice the section's children in.
121
+ if @arena.type(child_id) == NodeType::FOOTNOTES_SECTION
122
+ @arena.child_ids(child_id).each { |def_id| result << node(def_id, parent_spread: parent_spread) }
123
+ else
124
+ result << node(child_id, parent_spread: parent_spread)
125
+ end
126
+ end
127
+ result
128
+ end
129
+
130
+ def position(span)
131
+ start_loc = @document.source_map.line_column(span.start_byte)
132
+ end_loc = @document.source_map.line_column(span.end_byte)
133
+ {
134
+ "start" => {
135
+ "line" => start_loc[:line],
136
+ "column" => start_loc[:column],
137
+ "offset" => span.start_byte,
138
+ },
139
+ "end" => {
140
+ "line" => end_loc[:line],
141
+ "column" => end_loc[:column],
142
+ "offset" => span.end_byte,
143
+ },
144
+ }
145
+ end
146
+
147
+ def mdast_type_name(type_sym)
148
+ MDAST_TYPE_NAMES.fetch(type_sym, type_sym.to_s)
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedQuilt
4
+ class SourceMap
5
+ def initialize(source)
6
+ @source = source
7
+ @line_starts = build_line_starts(source)
8
+ end
9
+
10
+ def line_column(byte_offset)
11
+ line = (@line_starts.bsearch_index { |s| s > byte_offset } || @line_starts.length) - 1
12
+ line_start = @line_starts[line]
13
+ column = @source.byteslice(line_start, byte_offset - line_start).to_s.length
14
+ { line: line + 1, column: column }
15
+ end
16
+
17
+ private
18
+
19
+ def build_line_starts(source)
20
+ starts = [0]
21
+ pos = 0
22
+ while (idx = source.index("\n", pos))
23
+ starts << (idx + 1)
24
+ pos = idx + 1
25
+ end
26
+ starts
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedQuilt
4
+ class SourceSpan
5
+ attr_reader :start_byte, :end_byte
6
+
7
+ def initialize(start_byte, end_byte)
8
+ @start_byte = start_byte
9
+ @end_byte = end_byte
10
+ end
11
+
12
+ def length
13
+ @end_byte - @start_byte
14
+ end
15
+
16
+ def ==(other)
17
+ other.is_a?(SourceSpan) &&
18
+ other.start_byte == @start_byte &&
19
+ other.end_byte == @end_byte
20
+ end
21
+
22
+ def to_h
23
+ { start_byte: @start_byte, end_byte: @end_byte }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedQuilt
4
+ # Optional bundled stylesheets for standalone HTML output. `:none` (the
5
+ # default) embeds no CSS and leaves the bare document untouched; named
6
+ # themes load a stylesheet shipped under lib/red_quilt/themes/.
7
+ module Theme
8
+ DIR = File.expand_path("themes", __dir__)
9
+ private_constant :DIR
10
+
11
+ # Theme names that embed a bundled stylesheet (excludes :none).
12
+ NAMES = %i[default].freeze
13
+
14
+ module_function
15
+
16
+ # Returns the CSS for `name`, or nil for :none / nil (no embedded CSS).
17
+ # Raises ArgumentError for an unknown name.
18
+ def css(name)
19
+ name = (name || :none).to_sym
20
+ return nil if name == :none
21
+ unless NAMES.include?(name)
22
+ raise ArgumentError, "unknown theme #{name.inspect} (available: none, #{NAMES.join(', ')})"
23
+ end
24
+
25
+ (@cache ||= {})[name] ||= File.read(File.join(DIR, "#{name}.css")).freeze
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,87 @@
1
+ /* RedQuilt default theme — a compact, readable stylesheet for standalone
2
+ HTML output. Intentionally minimal: no syntax highlighting, no JS. */
3
+
4
+ body {
5
+ max-width: 54rem;
6
+ margin: 0 auto;
7
+ padding: 2rem 1rem 4rem;
8
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
9
+ font-size: 16px;
10
+ line-height: 1.6;
11
+ color: #1f2328;
12
+ background: #ffffff;
13
+ word-wrap: break-word;
14
+ }
15
+
16
+ h1, h2, h3, h4, h5, h6 {
17
+ margin: 1.6em 0 0.6em;
18
+ line-height: 1.25;
19
+ font-weight: 600;
20
+ }
21
+
22
+ h1 { font-size: 1.9em; }
23
+ h2 { font-size: 1.5em; }
24
+ h3 { font-size: 1.25em; }
25
+ h1, h2 { padding-bottom: 0.3em; border-bottom: 1px solid #d0d7de; }
26
+
27
+ p, ul, ol, blockquote, table, pre { margin: 0 0 1rem; }
28
+
29
+ a { color: #0969da; text-decoration: none; }
30
+ a:hover { text-decoration: underline; }
31
+
32
+ ul, ol { padding-left: 1.6em; }
33
+ li + li { margin-top: 0.2em; }
34
+
35
+ blockquote {
36
+ margin-left: 0;
37
+ padding: 0 1em;
38
+ color: #59636e;
39
+ border-left: 0.25em solid #d0d7de;
40
+ }
41
+
42
+ code {
43
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
44
+ font-size: 0.9em;
45
+ background: #eff1f3;
46
+ padding: 0.15em 0.35em;
47
+ border-radius: 4px;
48
+ }
49
+
50
+ pre {
51
+ background: #f6f8fa;
52
+ padding: 1rem;
53
+ border-radius: 6px;
54
+ overflow: auto;
55
+ }
56
+
57
+ pre code { background: none; padding: 0; font-size: 0.875em; }
58
+
59
+ table { border-collapse: collapse; }
60
+ th, td { padding: 0.4em 0.8em; border: 1px solid #d0d7de; }
61
+ th { background: #f6f8fa; }
62
+
63
+ hr { height: 1px; margin: 2rem 0; border: 0; background: #d0d7de; }
64
+
65
+ img { max-width: 100%; }
66
+
67
+ .footnotes {
68
+ margin-top: 2.5rem;
69
+ padding-top: 1rem;
70
+ font-size: 0.9em;
71
+ color: #59636e;
72
+ border-top: 1px solid #d0d7de;
73
+ }
74
+
75
+ /* Follow the OS / browser preference for dark mode. */
76
+ @media (prefers-color-scheme: dark) {
77
+ body { color: #e6edf3; background: #0d1117; }
78
+ a { color: #4493f8; }
79
+ h1, h2 { border-bottom-color: #30363d; }
80
+ blockquote { color: #9198a1; border-left-color: #30363d; }
81
+ code { background: #262c36; }
82
+ pre { background: #161b22; }
83
+ th, td { border-color: #30363d; }
84
+ th { background: #161b22; }
85
+ hr { background: #30363d; }
86
+ .footnotes { color: #9198a1; border-top-color: #30363d; }
87
+ }
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedQuilt
4
+ VERSION = "0.6.1"
5
+ end
data/lib/red_quilt.rb ADDED
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "red_quilt/version"
4
+ require_relative "red_quilt/node_type"
5
+ require_relative "red_quilt/source_span"
6
+ require_relative "red_quilt/line"
7
+ require_relative "red_quilt/indentation"
8
+ require_relative "red_quilt/source_map"
9
+ require_relative "red_quilt/arena"
10
+ require_relative "red_quilt/node_ref"
11
+ require_relative "red_quilt/diagnostic"
12
+ require_relative "red_quilt/plain_text"
13
+ require_relative "red_quilt/theme"
14
+ require_relative "red_quilt/document"
15
+ require_relative "red_quilt/inline"
16
+ require_relative "red_quilt/inline/html_entities"
17
+ require_relative "red_quilt/reference_definition"
18
+ require_relative "red_quilt/footnote_registry"
19
+ require_relative "red_quilt/footnote_definition"
20
+ require_relative "red_quilt/list"
21
+ require_relative "red_quilt/blockquote"
22
+ require_relative "red_quilt/block_parser"
23
+ require_relative "red_quilt/inline/token_kind"
24
+ require_relative "red_quilt/inline/tokens"
25
+ require_relative "red_quilt/inline/flanking"
26
+ require_relative "red_quilt/inline/lexer"
27
+ require_relative "red_quilt/inline/link_scanner"
28
+ require_relative "red_quilt/inline/builder"
29
+ require_relative "red_quilt/inline_pass"
30
+ require_relative "red_quilt/footnote_pass"
31
+ require_relative "red_quilt/extended_autolink_pass"
32
+ require_relative "red_quilt/lint_pass"
33
+ require_relative "red_quilt/renderer/html"
34
+ require_relative "red_quilt/renderer/mdast"
35
+
36
+ module RedQuilt
37
+ class Error < StandardError; end
38
+
39
+ class << self
40
+ def parse(source, allow_html: false, disallow_raw_html: false, extended_autolinks: false, footnotes: false, lint: false)
41
+ normalized = normalize_input(source)
42
+ arena = Arena.new(normalized)
43
+ footnote_registry = FootnoteRegistry.new if footnotes
44
+ block_parser = BlockParser.new(arena, footnotes: footnote_registry)
45
+ root_id = block_parser.parse
46
+ document = Document.new(normalized, arena, root_id,
47
+ allow_html: allow_html,
48
+ disallow_raw_html: disallow_raw_html,
49
+ references: block_parser.references,
50
+ footnotes: footnote_registry)
51
+ document.diagnostics.concat(block_parser.diagnostics)
52
+ InlinePass.new(document).apply
53
+ FootnotePass.new(document).apply if footnote_registry
54
+ ExtendedAutolinkPass.new(document).apply if extended_autolinks
55
+ LintPass.new(document).apply if lint
56
+ document
57
+ end
58
+
59
+ def render_html(source, allow_html: false, disallow_raw_html: false, extended_autolinks: false, footnotes: false, lint: false)
60
+ parse(source,
61
+ allow_html: allow_html,
62
+ disallow_raw_html: disallow_raw_html,
63
+ extended_autolinks: extended_autolinks,
64
+ footnotes: footnotes,
65
+ lint: lint).to_html
66
+ end
67
+
68
+ private
69
+
70
+ NUL_CHAR = 0.chr
71
+ REPLACEMENT_CHAR = 0xFFFD.chr(Encoding::UTF_8)
72
+ private_constant :NUL_CHAR, :REPLACEMENT_CHAR
73
+
74
+ # CommonMark normalization applied before parsing:
75
+ # - line endings: \r\n and lone \r -> \n (spec defines all three as line endings)
76
+ # - NUL (U+0000) -> U+FFFD (spec requires this replacement for security)
77
+ def normalize_input(source)
78
+ # Both substitutions rewrite the whole document, so skip each scan
79
+ # (and its full-string copy) when the trigger byte is absent -- the
80
+ # common case is LF-only text with no NUL.
81
+ source = source.gsub(/\r\n?/, "\n") if source.include?("\r")
82
+ source = source.gsub(NUL_CHAR, REPLACEMENT_CHAR) if source.include?(NUL_CHAR)
83
+ source
84
+ end
85
+ end
86
+ end
data/mise.toml ADDED
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ ruby = "4.0.5"
data/sig/red_quilt.rbs ADDED
@@ -0,0 +1,45 @@
1
+ module RedQuilt
2
+ VERSION: String
3
+
4
+ def self.parse: (String source, ?allow_html: bool) -> Document
5
+ def self.render_html: (String source, ?allow_html: bool) -> String
6
+
7
+ class Document
8
+ attr_reader source: String
9
+ attr_reader arena: Arena
10
+ attr_reader root_id: Integer
11
+
12
+ def root: () -> NodeRef
13
+ def to_html: () -> String
14
+ def to_ast: () -> Hash[Symbol, untyped]
15
+ def allow_html?: () -> bool
16
+ def source_map: () -> SourceMap
17
+ end
18
+
19
+ class NodeRef
20
+ include Enumerable[NodeRef]
21
+
22
+ attr_reader document: Document
23
+ attr_reader node_id: Integer
24
+
25
+ def type: () -> Symbol
26
+ def children: () -> Array[NodeRef]
27
+ def walk: () { (NodeRef) -> void } -> void
28
+ def walk: () -> Enumerator[NodeRef, void]
29
+ def find_all: (Symbol type) -> Array[NodeRef]
30
+ def to_h: () -> Hash[Symbol, untyped]
31
+ def text: () -> String?
32
+ def source_span: () -> SourceSpan?
33
+ def source_location: () -> { start_line: Integer, start_column: Integer, end_line: Integer, end_column: Integer }?
34
+ end
35
+
36
+ class Arena
37
+ end
38
+
39
+ class SourceMap
40
+ def initialize: (String source) -> void
41
+ def line_column: (Integer byte_offset) -> { line: Integer, column: Integer }
42
+ end
43
+
44
+ SourceSpan = Data[Integer, Integer]
45
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: red_quilt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ platform: ruby
6
+ authors:
7
+ - takahashim
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: A modern Markdown document processor in pure Ruby, with an arena-style
13
+ AST and full CommonMark spec test suite compliance.
14
+ email:
15
+ - takahashimm@gmail.com
16
+ executables:
17
+ - redquilt
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - ".rubocop_todo.yml"
24
+ - CHANGELOG.md
25
+ - README.md
26
+ - Rakefile
27
+ - ast-spec.md
28
+ - docs/architecture.md
29
+ - docs/arena-usage.md
30
+ - docs/commonmark-conformance.md
31
+ - exe/redquilt
32
+ - lib/red_quilt.rb
33
+ - lib/red_quilt/arena.rb
34
+ - lib/red_quilt/block_parser.rb
35
+ - lib/red_quilt/blockquote.rb
36
+ - lib/red_quilt/cli.rb
37
+ - lib/red_quilt/diagnostic.rb
38
+ - lib/red_quilt/document.rb
39
+ - lib/red_quilt/extended_autolink_pass.rb
40
+ - lib/red_quilt/footnote_definition.rb
41
+ - lib/red_quilt/footnote_pass.rb
42
+ - lib/red_quilt/footnote_registry.rb
43
+ - lib/red_quilt/indentation.rb
44
+ - lib/red_quilt/inline.rb
45
+ - lib/red_quilt/inline/builder.rb
46
+ - lib/red_quilt/inline/flanking.rb
47
+ - lib/red_quilt/inline/html_entities.rb
48
+ - lib/red_quilt/inline/lexer.rb
49
+ - lib/red_quilt/inline/link_scanner.rb
50
+ - lib/red_quilt/inline/token_kind.rb
51
+ - lib/red_quilt/inline/tokens.rb
52
+ - lib/red_quilt/inline_pass.rb
53
+ - lib/red_quilt/line.rb
54
+ - lib/red_quilt/lint_pass.rb
55
+ - lib/red_quilt/list.rb
56
+ - lib/red_quilt/node_ref.rb
57
+ - lib/red_quilt/node_type.rb
58
+ - lib/red_quilt/plain_text.rb
59
+ - lib/red_quilt/reference_definition.rb
60
+ - lib/red_quilt/renderer/html.rb
61
+ - lib/red_quilt/renderer/mdast.rb
62
+ - lib/red_quilt/source_map.rb
63
+ - lib/red_quilt/source_span.rb
64
+ - lib/red_quilt/theme.rb
65
+ - lib/red_quilt/themes/default.css
66
+ - lib/red_quilt/version.rb
67
+ - mise.toml
68
+ - sig/red_quilt.rbs
69
+ homepage: https://github.com/takahashim/red_quilt
70
+ licenses: []
71
+ metadata:
72
+ homepage_uri: https://github.com/takahashim/red_quilt
73
+ source_code_uri: https://github.com/takahashim/red_quilt
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 3.3.0
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 4.0.10
89
+ specification_version: 4
90
+ summary: CommonMark-based Markdown processor written in pure Ruby
91
+ test_files: []