red_quilt 0.7.1 → 0.8.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 +42 -0
- data/README.md +69 -7
- data/Rakefile +31 -0
- data/docs/api.md +15 -0
- data/docs/architecture.ja.md +1 -1
- data/docs/architecture.md +99 -0
- data/docs/arena-usage.ja.md +5 -5
- data/docs/arena-usage.md +423 -0
- data/docs/commonmark-conformance.md +316 -0
- data/lib/red_quilt/arena.rb +96 -0
- data/lib/red_quilt/block_parser.rb +22 -384
- data/lib/red_quilt/cli.rb +14 -2
- data/lib/red_quilt/code_block.rb +139 -0
- data/lib/red_quilt/document.rb +86 -6
- data/lib/red_quilt/footnote_anchors.rb +24 -0
- data/lib/red_quilt/footnote_pass.rb +6 -2
- data/lib/red_quilt/frontmatter.rb +54 -0
- data/lib/red_quilt/html_block.rb +161 -0
- data/lib/red_quilt/indentation.rb +35 -0
- data/lib/red_quilt/inline/builder.rb +9 -186
- data/lib/red_quilt/inline/emphasis_resolver.rb +184 -0
- data/lib/red_quilt/inline/url_sanitizer.rb +64 -0
- data/lib/red_quilt/line.rb +6 -1
- data/lib/red_quilt/lint_pass.rb +2 -2
- data/lib/red_quilt/node_ref.rb +20 -11
- data/lib/red_quilt/renderer/html.rb +48 -26
- data/lib/red_quilt/renderer/mdast.rb +11 -11
- data/lib/red_quilt/table.rb +97 -0
- data/lib/red_quilt/version.rb +1 -1
- data/lib/red_quilt.rb +19 -4
- data/sig/red_quilt.rbs +18 -0
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 56e09a19cfb78fad2a7e9a377f3ec6b9033d2160d4c126719e8220245b340709
|
|
4
|
+
data.tar.gz: 35bcb8de686345a72b9d2edf0261c7b201fb138047b571e3cc14b4f62be2671a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a5ad64e49f61ddcca8c3453b28ab06e7c04d76da574d82e6185b9a175189f313e043dcb586ff4293ad801b6bbb521ecca902f4dd9cac630186db97a2d8de5b91
|
|
7
|
+
data.tar.gz: fc3764a74f06f1d902afd5eeba1e572ddb97f3fa1c9306f4de937e1929937d22830f856c77b03d2e1fc658be3310d7f7535cb994a7945cf7f5f18ea52e0416c4
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,48 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `NodeRef#info`: returns the fence info string of a code block (e.g. `ruby`
|
|
13
|
+
in ` ```ruby `, or `vtt audio="x.mp3"`); `""` for code blocks without one
|
|
14
|
+
and for every other node type. The raw code content remains available via
|
|
15
|
+
`NodeRef#text`.
|
|
16
|
+
- `Renderer::HTML#render_fragment(nodes)`: renders an Array of `NodeRef` in
|
|
17
|
+
order and returns the HTML fragment without affecting the main render
|
|
18
|
+
output. Renderer state shared across nodes (e.g. the heading-id slugger) is
|
|
19
|
+
preserved between calls. Lets callers that partition a document render the
|
|
20
|
+
pieces separately without reaching into renderer internals.
|
|
21
|
+
- `Arena` semantic payload accessors (`heading_level`, `list_ordered?`,
|
|
22
|
+
`code_block_info`, `link_destination`, `footnote_number`, …) for callers
|
|
23
|
+
that walk `Document#arena`, replacing direct use of the raw `int1`/`str2`
|
|
24
|
+
columns.
|
|
25
|
+
|
|
26
|
+
## [0.7.2] - 2026-06-23
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Opt-in YAML frontmatter support via the `frontmatter:` option on `parse` /
|
|
31
|
+
`render_html` and the `--frontmatter` CLI flag (off by default). A leading
|
|
32
|
+
`---` … `---` block is removed from the rendered body and exposed as
|
|
33
|
+
`Document#frontmatter`; in standalone output its `title` / `lang` keys fill
|
|
34
|
+
in `<title>` / `<html lang>`.
|
|
35
|
+
- Opt-in Mermaid diagram support via the `mermaid:` option on `render_html` /
|
|
36
|
+
`Document#to_html` and the `--mermaid` CLI flag (off by default). Fenced
|
|
37
|
+
` ```mermaid ` code blocks render as `<pre class="mermaid">` containers; in
|
|
38
|
+
standalone output the mermaid.js runtime is loaded from a CDN and each
|
|
39
|
+
diagram is made interactive (wheel zoom, drag pan, +/-/reset controls) with
|
|
40
|
+
svg-pan-zoom.
|
|
41
|
+
|
|
42
|
+
## [0.7.1] - 2026-06-06
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- `--open` CLI flag: render the Markdown to a standalone HTML file and open it
|
|
47
|
+
in the default browser (forces `--standalone`; writes under `Dir.tmpdir`
|
|
48
|
+
when `-o` is not given).
|
|
49
|
+
|
|
8
50
|
## [0.7.0] - 2026-05-29
|
|
9
51
|
|
|
10
52
|
### Added
|
data/README.md
CHANGED
|
@@ -48,6 +48,7 @@ RedQuilt.render_html("Hi <em>tag</em>", allow_html: true)
|
|
|
48
48
|
| `extended_autolinks:` | `false` | GFM: linkify bare `http(s)://` / `www.` / email addresses |
|
|
49
49
|
| `footnotes:` | `false` | GFM footnotes (see below) |
|
|
50
50
|
| `lint:` | `false` | Collect lint diagnostics (empty links, missing image alt, heading-level skips) |
|
|
51
|
+
| `frontmatter:` | `false` | Parse leading YAML frontmatter (`---`) as metadata (see below) |
|
|
51
52
|
|
|
52
53
|
### Footnotes (opt-in)
|
|
53
54
|
|
|
@@ -75,14 +76,66 @@ doc.diagnostics.first.severity # => :warning
|
|
|
75
76
|
### Heading anchors (opt-in)
|
|
76
77
|
|
|
77
78
|
`render_html` / `to_html` accept `heading_ids:` to give every heading a
|
|
78
|
-
slugified `id` for anchor links.
|
|
79
|
-
intact, so Japanese headings stay readable; duplicates get `-1`, `-2` suffixes.
|
|
79
|
+
slugified `id` for anchor links.
|
|
80
80
|
|
|
81
81
|
```ruby
|
|
82
82
|
RedQuilt.render_html("# Hello World\n\n## はじめに", heading_ids: true)
|
|
83
83
|
# => "<h1 id=\"hello-world\">Hello World</h1>\n<h2 id=\"はじめに\">はじめに</h2>\n"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
### Mermaid diagrams (opt-in)
|
|
87
|
+
|
|
88
|
+
`render_html` / `to_html` accept `mermaid:` to render ` ```mermaid ` fenced
|
|
89
|
+
code blocks for [mermaid.js](https://mermaid.js.org/).
|
|
90
|
+
In standalone output the mermaid.js runtime is also loaded from a CDN.
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
RedQuilt.render_html("```mermaid\ngraph LR\n A --> B\n```", mermaid: true)
|
|
94
|
+
# => "<pre class=\"mermaid\">graph LR\n A --> B\n</pre>\n"
|
|
95
|
+
|
|
96
|
+
# Full page that renders the diagram in a browser (CDN script included):
|
|
97
|
+
RedQuilt.parse("```mermaid\ngraph LR\n A --> B\n```")
|
|
98
|
+
.to_html(standalone: true, mermaid: true)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
In standalone output each diagram is made interactive with
|
|
102
|
+
[svg-pan-zoom](https://github.com/bumbu/svg-pan-zoom) (loaded from a CDN).
|
|
103
|
+
|
|
104
|
+
### YAML frontmatter (opt-in)
|
|
105
|
+
|
|
106
|
+
`parse` / `render_html` accept `frontmatter:` to extract a leading YAML
|
|
107
|
+
frontmatter block (the `---` … `---` fences used by Jekyll, Hugo).
|
|
108
|
+
The block is parsed with `Psych.safe_load` and removed from the rendered body;
|
|
109
|
+
the parsed Hash is exposed as `Document#frontmatter`.
|
|
110
|
+
|
|
111
|
+
```ruby
|
|
112
|
+
doc = RedQuilt.parse(<<~MD, frontmatter: true)
|
|
113
|
+
---
|
|
114
|
+
title: My Page
|
|
115
|
+
lang: ja
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
# Body
|
|
119
|
+
MD
|
|
120
|
+
doc.frontmatter # => {"title" => "My Page", "lang" => "ja"}
|
|
121
|
+
doc.to_html # => "<h1>Body</h1>\n" (frontmatter stripped)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
In standalone output the frontmatter's `title` / `lang` fill in `<title>` /
|
|
125
|
+
`<html lang>` when no explicit argument is given (explicit argument >
|
|
126
|
+
frontmatter > default):
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
doc.to_html(standalone: true)
|
|
130
|
+
# <html lang="ja"> … <title>My Page</title> …
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The feature is opt-in, so a bare `---` is never mistaken for frontmatter
|
|
134
|
+
unless `frontmatter: true` is passed. Frontmatter lines are blanked rather
|
|
135
|
+
than deleted, so body source spans and diagnostic line numbers stay relative
|
|
136
|
+
to the start of the file. Invalid YAML records a `:frontmatter` warning
|
|
137
|
+
diagnostic and leaves `Document#frontmatter` as `nil` without raising.
|
|
138
|
+
|
|
86
139
|
### Tilt integration
|
|
87
140
|
|
|
88
141
|
RedQuilt ships a [Tilt](https://github.com/jeremyevans/tilt) adapter.
|
|
@@ -100,13 +153,13 @@ Native options (`allow_html:`, `footnotes:`, …) pass straight through; Tilt's
|
|
|
100
153
|
## Documentation
|
|
101
154
|
|
|
102
155
|
- [API reference](docs/api.md) — `Document` / `NodeRef` / `SourceSpan`, supported syntax, and usage examples
|
|
103
|
-
- [Architecture overview](docs/architecture.
|
|
104
|
-
- [Arena usage guide](docs/arena-usage.
|
|
105
|
-
- [CommonMark conformance notes](docs/commonmark-conformance.
|
|
156
|
+
- [Architecture overview](docs/architecture.md) ([日本語](docs/architecture.ja.md))
|
|
157
|
+
- [Arena usage guide](docs/arena-usage.md) ([日本語](docs/arena-usage.ja.md))
|
|
158
|
+
- [CommonMark conformance notes](docs/commonmark-conformance.md) ([日本語](docs/commonmark-conformance.ja.md))
|
|
106
159
|
|
|
107
160
|
## CommonMark Compatibility
|
|
108
161
|
|
|
109
|
-
RedQuilt achieves 100% compliance with the CommonMark v0.31.2
|
|
162
|
+
RedQuilt achieves 100% compliance with the CommonMark v0.31.2 test cases.
|
|
110
163
|
See the [conformance notes](docs/commonmark-conformance.ja.md) for GFM
|
|
111
164
|
extensions and intentional deviations.
|
|
112
165
|
|
|
@@ -143,6 +196,9 @@ redquilt -o output.html input.md
|
|
|
143
196
|
|
|
144
197
|
# Render and open the result in the default browser
|
|
145
198
|
redquilt --open input.md
|
|
199
|
+
|
|
200
|
+
# Render mermaid code blocks as diagrams (loads mermaid.js from a CDN)
|
|
201
|
+
redquilt --mermaid --open input.md
|
|
146
202
|
```
|
|
147
203
|
|
|
148
204
|
### Options
|
|
@@ -164,6 +220,10 @@ redquilt --open input.md
|
|
|
164
220
|
--open Write HTML to a file and open it in the default
|
|
165
221
|
browser (forces --standalone; uses a file under
|
|
166
222
|
Dir.tmpdir when -o is not given)
|
|
223
|
+
--mermaid Render `mermaid` code blocks as diagrams (loads
|
|
224
|
+
mermaid.js from a CDN in standalone output)
|
|
225
|
+
--frontmatter Parse leading YAML frontmatter (---) as metadata;
|
|
226
|
+
fills <title>/lang in standalone output
|
|
167
227
|
--diagnostics Print diagnostics to stderr
|
|
168
228
|
--diagnostics-only Print diagnostics only (suppress output)
|
|
169
229
|
-h, --help Show help
|
|
@@ -216,7 +276,9 @@ RedQuilt.render_html(user_markdown, allow_html: true)
|
|
|
216
276
|
bundle exec rake spec
|
|
217
277
|
```
|
|
218
278
|
|
|
219
|
-
Runs
|
|
279
|
+
Runs the full CommonMark 0.31.2 conformance suite (all 652 official examples,
|
|
280
|
+
parsed directly from `spec/fixtures/cmark_spec-0.31.2.md`) plus RedQuilt's own
|
|
281
|
+
feature tests — 1000 examples in total.
|
|
220
282
|
|
|
221
283
|
### Benchmark
|
|
222
284
|
|
data/Rakefile
CHANGED
|
@@ -6,3 +6,34 @@ require "rspec/core/rake_task"
|
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
|
8
8
|
task default: :spec
|
|
9
|
+
|
|
10
|
+
desc "Report CommonMark spec conformance, broken down by section"
|
|
11
|
+
task :conformance do
|
|
12
|
+
require_relative "lib/red_quilt"
|
|
13
|
+
require_relative "spec/support/commonmark_spec_loader"
|
|
14
|
+
|
|
15
|
+
examples = CommonMarkSpecLoader.examples
|
|
16
|
+
sections = examples.each_with_object({}) do |example, acc|
|
|
17
|
+
stats = acc[example[:section]] ||= { pass: 0, total: 0 }
|
|
18
|
+
stats[:total] += 1
|
|
19
|
+
actual = RedQuilt.parse(example[:markdown], allow_html: true).to_html
|
|
20
|
+
stats[:pass] += 1 if actual == example[:html]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
total = { pass: sections.values.sum { |s| s[:pass] }, total: examples.size }
|
|
24
|
+
width = sections.keys.map(&:length).max
|
|
25
|
+
divider = " #{'-' * width} ---------- -------"
|
|
26
|
+
|
|
27
|
+
puts "CommonMark #{CommonMarkSpecLoader::VERSION} conformance", ""
|
|
28
|
+
puts format(" %-#{width}s %-10s %s", "Section", "Pass/Total", "Rate")
|
|
29
|
+
puts divider
|
|
30
|
+
sections.each do |name, stats|
|
|
31
|
+
rate = stats[:pass].fdiv(stats[:total]) * 100
|
|
32
|
+
puts format(" %-#{width}s %4d / %4d %5.1f%%", name, stats[:pass], stats[:total], rate)
|
|
33
|
+
end
|
|
34
|
+
puts divider
|
|
35
|
+
rate = total[:pass].fdiv(total[:total]) * 100
|
|
36
|
+
puts format(" %-#{width}s %4d / %4d %5.1f%%", "TOTAL", total[:pass], total[:total], rate)
|
|
37
|
+
|
|
38
|
+
abort("\nConformance is below 100%.") unless total[:pass] == total[:total]
|
|
39
|
+
end
|
data/docs/api.md
CHANGED
|
@@ -18,11 +18,25 @@ doc.source_map # Line/column lookup (lazy memoized)
|
|
|
18
18
|
doc.diagnostics # Array of RedQuilt::Diagnostic collected while parsing
|
|
19
19
|
doc.allow_html? # Check HTML pass-through setting
|
|
20
20
|
doc.disallow_raw_html? # Check GFM disallowed-raw-HTML filtering setting
|
|
21
|
+
doc.frontmatter # Parsed YAML frontmatter Hash, or nil (see below)
|
|
21
22
|
|
|
22
23
|
# Standalone document with an embedded theme:
|
|
23
24
|
doc.to_html(standalone: true, theme: :default, title: "My Doc", lang: "en")
|
|
24
25
|
# theme: :default (compact, dark-mode-aware stylesheet) or :none (bare).
|
|
25
26
|
# css: "style.css" links an external stylesheet instead.
|
|
27
|
+
|
|
28
|
+
# Render `mermaid` code blocks as <pre class="mermaid"> diagrams; in
|
|
29
|
+
# standalone mode the mermaid.js runtime is loaded from a CDN too.
|
|
30
|
+
doc.to_html(standalone: true, mermaid: true)
|
|
31
|
+
|
|
32
|
+
# Parse a leading YAML frontmatter block (--- ... ---). Off by default; when
|
|
33
|
+
# enabled the block is removed from the rendered body and exposed as a Hash.
|
|
34
|
+
doc = RedQuilt.parse("---\ntitle: Hi\nlang: ja\n---\n\n# Body", frontmatter: true)
|
|
35
|
+
doc.frontmatter # => {"title" => "Hi", "lang" => "ja"} (nil when absent/disabled)
|
|
36
|
+
# In standalone output frontmatter title/lang fill <title>/<html lang> unless
|
|
37
|
+
# an explicit argument overrides them. Invalid YAML adds a :frontmatter
|
|
38
|
+
# warning diagnostic and leaves doc.frontmatter as nil.
|
|
39
|
+
doc.to_html(standalone: true)
|
|
26
40
|
```
|
|
27
41
|
|
|
28
42
|
## NodeRef (AST node wrapper)
|
|
@@ -36,6 +50,7 @@ node.children # Array[NodeRef]
|
|
|
36
50
|
node.walk # Enumerator[NodeRef] or { |node| ... } block
|
|
37
51
|
node.find_all(:link) # Array[NodeRef] with matching type
|
|
38
52
|
node.text # String (concatenated child text)
|
|
53
|
+
node.info # String fence info of a code block (e.g. "ruby")
|
|
39
54
|
|
|
40
55
|
# Position information (byte offset)
|
|
41
56
|
node.source_span # SourceSpan with start_byte, end_byte
|
data/docs/architecture.ja.md
CHANGED
|
@@ -35,7 +35,7 @@ Source (Markdown String)
|
|
|
35
35
|
## 各ステージの責務
|
|
36
36
|
|
|
37
37
|
### `RedQuilt.normalize_input`
|
|
38
|
-
CommonMark§2.3/2.4の最小前処理。`\r\n`/`\r`→`\n`の行末正規化と、NUL→U+FFFDの置換だけを行う。
|
|
38
|
+
- CommonMark§2.3/2.4の最小前処理。`\r\n`/`\r`→`\n`の行末正規化と、NUL→U+FFFDの置換だけを行う。
|
|
39
39
|
|
|
40
40
|
### BlockParser
|
|
41
41
|
- 行分割: sourceを`Line` Struct配列へ。各行はbyte spanで保持する。
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# RedQuilt Architecture Overview
|
|
2
|
+
|
|
3
|
+
This document gives a high-level view of how RedQuilt is structured.
|
|
4
|
+
|
|
5
|
+
## Pipeline
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Source (Markdown String)
|
|
9
|
+
│
|
|
10
|
+
▼ RedQuilt.normalize_input (lib/red_quilt.rb)
|
|
11
|
+
│
|
|
12
|
+
▼ BlockParser (lib/red_quilt/block_parser.rb)
|
|
13
|
+
│ dispatch / container parsers / build_lines
|
|
14
|
+
│ (list.rb, blockquote.rb, reference_definition.rb)
|
|
15
|
+
│
|
|
16
|
+
▼ Arena (raw inline spans)
|
|
17
|
+
│ The body of each paragraph / heading / table cell is kept
|
|
18
|
+
│ as a byte span or a str1 literal.
|
|
19
|
+
│
|
|
20
|
+
▼ InlinePass (lib/red_quilt/inline_pass.rb)
|
|
21
|
+
│ ├─ Inline::Lexer (lib/red_quilt/inline/lexer.rb)
|
|
22
|
+
│ │ byte scan -> Tokens (parallel array)
|
|
23
|
+
│ └─ Inline::Builder (lib/red_quilt/inline/builder.rb)
|
|
24
|
+
│ linear pass -> process_emphasis (CommonMark §6.2)
|
|
25
|
+
│
|
|
26
|
+
▼ Arena (inline resolved)
|
|
27
|
+
│
|
|
28
|
+
▼ (option) FootnotePass (footnotes: true)
|
|
29
|
+
▼ (option) ExtendedAutolinkPass (extended_autolinks: true)
|
|
30
|
+
▼ (option) LintPass (lint: true)
|
|
31
|
+
│
|
|
32
|
+
▼ Renderer::HTML (lib/red_quilt/renderer/html.rb)
|
|
33
|
+
walk the arena and append to a mutable String
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Responsibility of each stage
|
|
37
|
+
|
|
38
|
+
### `RedQuilt.normalize_input`
|
|
39
|
+
- Minimal preprocessing required by CommonMark §2.3 / §2.4. It only normalizes
|
|
40
|
+
line endings (`\r\n` / `\r` -> `\n`) and replaces NUL with U+FFFD.
|
|
41
|
+
|
|
42
|
+
### BlockParser
|
|
43
|
+
- Line splitting: turn the source into an array of `Line` structs. Each line is
|
|
44
|
+
kept as a byte span.
|
|
45
|
+
- Dispatch: decide the block kind from the first byte of the line
|
|
46
|
+
(`paragraph_only_line?` quickly routes non-block lines).
|
|
47
|
+
- Container delegation: lists and blockquotes are delegated to `List::Parser`
|
|
48
|
+
and `Blockquote::Parser`, which call `parse_lines` recursively.
|
|
49
|
+
- Collecting and excluding definitions: link reference definitions (the
|
|
50
|
+
reference table) and opt-in footnote definitions (`FootnoteRegistry`) are
|
|
51
|
+
pulled out of the body flow and gathered in dedicated collectors.
|
|
52
|
+
- Column calculation: indentation that includes tab expansion is delegated to
|
|
53
|
+
`Indentation`.
|
|
54
|
+
- Output: build block nodes in the Arena, with inline content still unresolved.
|
|
55
|
+
|
|
56
|
+
### InlinePass / Inline::Lexer / Inline::Builder
|
|
57
|
+
- Target selection: scan and process each inline target (paragraph / heading /
|
|
58
|
+
table cell).
|
|
59
|
+
- Lexer: scan the target's byte span, or the range of a str1 literal, into
|
|
60
|
+
Tokens (a parallel array).
|
|
61
|
+
- Builder, step 1 (linear_pass): resolve code spans, links, images, autolinks,
|
|
62
|
+
and simple inlines.
|
|
63
|
+
- Builder, step 2 (process_emphasis): collapse the delimiter stack to finalize
|
|
64
|
+
emphasis / strong / strikethrough (CommonMark §6.2; strikethrough is a GFM
|
|
65
|
+
extension).
|
|
66
|
+
- Footnote references: resolve `[^label]` through `FootnoteRegistry`, number
|
|
67
|
+
them in first-reference order, and create a `FOOTNOTE_REFERENCE`.
|
|
68
|
+
|
|
69
|
+
### FootnotePass (`footnotes: true`)
|
|
70
|
+
- Reordering: sort the definitions under `FOOTNOTES_SECTION` (at the end of the
|
|
71
|
+
root) into first-reference order.
|
|
72
|
+
- Pruning: detach unreferenced definitions.
|
|
73
|
+
- Section removal: if there are no references at all, remove the section itself.
|
|
74
|
+
|
|
75
|
+
### Renderer::HTML
|
|
76
|
+
- Walk: walk the arena recursively and append directly with `<<` to a mutable
|
|
77
|
+
String opened with `+""`.
|
|
78
|
+
- Raw HTML: `allow_html` switches between passing HTML through and escaping it;
|
|
79
|
+
`disallow_raw_html` filters HTML using GFM "Disallowed Raw HTML".
|
|
80
|
+
- Footnotes: render `FOOTNOTE_REFERENCE` as a sup link, and the trailing
|
|
81
|
+
`FOOTNOTES_SECTION` as `<section class="footnotes">` with backrefs.
|
|
82
|
+
|
|
83
|
+
## Where the main subsystems live
|
|
84
|
+
|
|
85
|
+
| Area | Files |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Entry point / input normalization | `lib/red_quilt.rb` |
|
|
88
|
+
| Public API | `lib/red_quilt/document.rb`, `node_ref.rb` |
|
|
89
|
+
| Arena | `lib/red_quilt/arena.rb` |
|
|
90
|
+
| Block parsing | `block_parser.rb`, `list.rb`, `blockquote.rb`, `indentation.rb` |
|
|
91
|
+
| Reference definitions | `reference_definition.rb` |
|
|
92
|
+
| Footnotes (opt-in) | `footnote_definition.rb`, `footnote_registry.rb`, `footnote_pass.rb` |
|
|
93
|
+
| Inline parsing | `inline.rb`, `inline/lexer.rb`, `inline/tokens.rb`, `inline/flanking.rb`, `inline/builder.rb`, `inline/link_scanner.rb` |
|
|
94
|
+
| Inline entities | `inline/html_entities.rb` |
|
|
95
|
+
| HTML / MDAST output | `renderer/html.rb`, `renderer/mdast.rb` |
|
|
96
|
+
| Extension passes | `inline_pass.rb`, `footnote_pass.rb`, `extended_autolink_pass.rb`, `lint_pass.rb` |
|
|
97
|
+
| Source positions | `source_span.rb`, `source_map.rb` |
|
|
98
|
+
| Diagnostics | `diagnostic.rb` |
|
|
99
|
+
| CLI | `cli.rb`, `exe/redquilt` |
|
data/docs/arena-usage.ja.md
CHANGED
|
@@ -92,7 +92,7 @@ ArenaはASTを「オブジェクトのツリー」ではなく[parallel array](h
|
|
|
92
92
|
- メモリ局所性が良く、GC圧が小さい
|
|
93
93
|
- ノードを「軽い」値として扱えるのでRenderer / Builderをinline化しやすい
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
#### 列(column)一覧
|
|
96
96
|
|
|
97
97
|
|列名|用途|
|
|
98
98
|
|------|------|
|
|
@@ -183,7 +183,7 @@ Arenaの公開メソッドは以下の3レイヤーに分けて読むと意図
|
|
|
183
183
|
|
|
184
184
|
各NodeTypeがどのint / strスロットを使うかは規約で決まっています。以下が現在の規約です。
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
#### Blockノード
|
|
187
187
|
|
|
188
188
|
| NodeType | int1 | int2 | int3 | str1 | str2 |
|
|
189
189
|
|----------|------|------|------|------|------|
|
|
@@ -202,7 +202,7 @@ Arenaの公開メソッドは以下の3レイヤーに分けて読むと意図
|
|
|
202
202
|
| `FOOTNOTE_DEFINITION` | - | - | - | 正規化済みlabel | - |
|
|
203
203
|
| `FOOTNOTES_SECTION` | - | - | - | - | - |
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
#### Inlineノード
|
|
206
206
|
|
|
207
207
|
| NodeType | int1 | int2 | int3 | str1 | str2 |
|
|
208
208
|
|----------|------|------|------|------|------|
|
|
@@ -219,7 +219,7 @@ Arenaの公開メソッドは以下の3レイヤーに分けて読むと意図
|
|
|
219
219
|
|
|
220
220
|
> footnoteは`footnotes: true`時のみ生成されます。`FOOTNOTES_SECTION`はroot直下の最後の子として置かれ(span-less、`source_start: -1`)、参照された`FOOTNOTE_DEFINITION`を初回参照順に保持します。backrefの個数はfootnote番号とlabelからrender時に算出します。
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
#### Source spanの慣習
|
|
223
223
|
|
|
224
224
|
- `source_start` / `source_len`: 元documentのbytes (絶対byte offset)
|
|
225
225
|
- `source_start < 0`: spanなし。leafノードでは内容を`str1`にliteralとして持つことが多いが、container inlineは子ノードだけを持つ場合がある。
|
|
@@ -334,7 +334,7 @@ arena.update_span(text_id, 0, 12)
|
|
|
334
334
|
|
|
335
335
|
## 6. パフォーマンス上の注意
|
|
336
336
|
|
|
337
|
-
|
|
337
|
+
#### ホットパスでは`each_child`を使う
|
|
338
338
|
|
|
339
339
|
ブロック直yieldでEnumerator allocationを避ける。`child_ids`は外部API用
|
|
340
340
|
|