carve-lang 0.1.1 → 0.1.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
- data/CHANGELOG.md +159 -1
- data/README.md +8 -4
- data/ext/carve/Cargo.lock +96 -69
- data/ext/carve/Cargo.toml +3 -2
- data/ext/carve/src/lib.rs +76 -3
- data/lib/carve/version.rb +1 -1
- data/lib/carve.rb +13 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '092afb8611f9491f14b1bdc5e74730dc30fd5efd269a3cf153246d8181e0e94c'
|
|
4
|
+
data.tar.gz: 57b9ce435040eb96ff5148a2ce15e0369bcb6f696bbf22422cb76ce42c60d1a9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8bfb7fea75aa1819fd2bde47740d428ba1c3846d004f5ca4e7fb11e89041750ecd7992ed3913fad42c4a627bbc5842e9e0adf66369f45c71499e34d623a3158
|
|
7
|
+
data.tar.gz: 18f13425d6701f44da146ee93c312acd0e8dec16a76fb55ab7995deadcf7931fbdd9fa8c666d19e7f153b7cd8b19d490cbe42e4389a0bfa9fe3be5183c65c64a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,162 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.3] - 2026-09-08
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- The engine moves from carve-rs `da45f9d2` to `42df4092`, 46 commits, clearing
|
|
15
|
+
the binding-parity drift the nightly run found on 34 corpus documents (#110).
|
|
16
|
+
A comment leaf span begins at its markup, an emptied definition description
|
|
17
|
+
narrows to its marker line, a footnote nested past a footnote body becomes its
|
|
18
|
+
own note, a nested item's lead fence or colon container takes its flush-left
|
|
19
|
+
body, and an all-blank or lone-pipe row is no longer read as a table (the lone
|
|
20
|
+
pipe no longer panics).
|
|
21
|
+
- The engine moves from carve-rs `2e9c43f2` to `da45f9d2`, 20 commits. A colon
|
|
22
|
+
followed by a space and a tab opens no description, an authored task state
|
|
23
|
+
reaches the tree and the HTML, a titled medium emits one title attribute, an
|
|
24
|
+
empty external link target is omitted, and a table continuation survives Djot
|
|
25
|
+
migration. The stale pin is what failed PART 12 binding parity in
|
|
26
|
+
markup-carve/carve#1877 - a binding has no vote of its own.
|
|
27
|
+
|
|
28
|
+
## [0.1.2] - 2026-08-27
|
|
29
|
+
|
|
30
|
+
### Security
|
|
31
|
+
|
|
32
|
+
- The gem is published through RubyGems trusted publishing rather than a
|
|
33
|
+
long-lived API key, and the gemspec sets `rubygems_mfa_required`, so RubyGems
|
|
34
|
+
refuses a push from an account without MFA (#81).
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- The engine moves from carve-rs `0.1.3` (`a33c42ad`), which `0.1.1` shipped, to
|
|
39
|
+
`bd19414d` - 106 commits across four pin bumps (#80, #82, #84, #87). Rendering
|
|
40
|
+
changes an existing document can see: a column's alignment defaults come from
|
|
41
|
+
the header section, an explicit alignment run is validated and inherited, and
|
|
42
|
+
a table cell's marker run must end at a space; tables gained semantic row
|
|
43
|
+
partitions and a list table can carry local headers; a braced hyphen pair is
|
|
44
|
+
an en dash, an empty brace pair is text, and the doubled run is the canonical
|
|
45
|
+
arrow; a hyphen run opening a word after whitespace is a flag, not a dash; a
|
|
46
|
+
continuation marker attaches only a flush-left block; the footnote backlink
|
|
47
|
+
has an accessible name; a caption no longer disables a diagram fence's preset;
|
|
48
|
+
the first code group is numbered like every other one; a heading at a content
|
|
49
|
+
column leaves no paragraph open, and a definition at a list item's content
|
|
50
|
+
column closes its paragraph; an all-blank raw payload stays distinct from an
|
|
51
|
+
absent one; and depth limits guard every recursive parse, render and AST-JSON
|
|
52
|
+
path. `<thead>` and `<tfoot>` also write one row per line, which changes the
|
|
53
|
+
emitted HTML without changing what it renders. The last bump adds: three blank
|
|
54
|
+
lines are a hard list boundary rather than a wide gap between two items, so a
|
|
55
|
+
document that used the run as spacing now parses as two lists; a heading id
|
|
56
|
+
can opt in to ASCII folding; a tab control renders as a button and a code
|
|
57
|
+
group takes the mode option; and a `%%` line a verbatim run has already
|
|
58
|
+
swallowed no longer produces a comment node after that run, which changes the
|
|
59
|
+
tree without changing the HTML (#84).
|
|
60
|
+
The fourth bump is 18 further commits, and over the spec corpus exactly one
|
|
61
|
+
document's HTML moves with it: a list marker at an item's content column
|
|
62
|
+
opens a sublist whether or not it is the item's first, so a marker that
|
|
63
|
+
follows a blank line and a paragraph inside an item no longer joins that
|
|
64
|
+
paragraph (markup-carve/carve-rs#1251). A further 104 documents change only
|
|
65
|
+
their reported positions, because a container's span now starts at its
|
|
66
|
+
opening markup and ends at its last placed child, and a definition list's
|
|
67
|
+
likewise (markup-carve/carve-rs#1238, markup-carve/carve-rs#1248,
|
|
68
|
+
markup-carve/carve-rs#1252). Nothing else an existing document can see
|
|
69
|
+
changes (#87).
|
|
70
|
+
- The engine then moves from `bd19414d` to `f2fbb24c` - 39 further commits
|
|
71
|
+
(#91). A container with no closer ends at its last placed child rather than
|
|
72
|
+
one codepoint past it, which is the PART 12 §4 extent defect this gem was
|
|
73
|
+
still the one implementation reporting (markup-carve/carve-rs#1308, #89); a
|
|
74
|
+
footnote continuation survives a blank run (markup-carve/carve-rs#1295); and
|
|
75
|
+
a list takes PART 9 §17 L7's consumed `loose` attribute, which loosens the
|
|
76
|
+
list instead of being emitted on it and which `Carve.parse` publishes on a
|
|
77
|
+
definition list as a `loose` field (markup-carve/carve-rs#1304). Seven corpus
|
|
78
|
+
documents move with the bump and all seven are documents the corpus gained,
|
|
79
|
+
so nothing that already rendered correctly changed.
|
|
80
|
+
- The embedded engine moves to carve-rs `42a952cb`. An indented lone image now
|
|
81
|
+
parses as a paragraph holding an inline image rather than a block image
|
|
82
|
+
(markup-carve/carve#1660, markup-carve/carve-rs#1347). AST only - the
|
|
83
|
+
rendered HTML is unchanged on every corpus document (#93).
|
|
84
|
+
- The embedded engine moves from `42a952cb` to `468e71af` - 70 further commits
|
|
85
|
+
across three pin bumps (#96, #97, #98), and each of the three changes what an
|
|
86
|
+
existing document renders as. The first two settle one rule between them: a
|
|
87
|
+
list item's content column is measured from the bare marker, so neither the
|
|
88
|
+
task checkbox nor a marker-attached attribute block widens it
|
|
89
|
+
(markup-carve/carve-rs#1364, markup-carve/carve-rs#1374,
|
|
90
|
+
markup-carve/carve-rs#1379). `-{#k} [x] a` has content column 2, so a `# h`
|
|
91
|
+
written under it at column 2 opens a heading inside the item where the wider
|
|
92
|
+
column made it lazy paragraph text. Also in those two: a lone image at an
|
|
93
|
+
item's content column keeps the item's looseness, restoring the `<p>` wrapper
|
|
94
|
+
the item used to drop (markup-carve/carve-rs#1359); the ANSI quote bar
|
|
95
|
+
reports containment, so a quoted heading, code block, table, thematic break
|
|
96
|
+
and lone image keep the bar and a quoted list's bar sits outside its marker
|
|
97
|
+
(markup-carve/carve-rs#1363); and on the import side an imported heading
|
|
98
|
+
records its id, an imported task item comes back a task item, an input's type
|
|
99
|
+
matches the checkbox keyword case-insensitively, an HTML comment imports as a
|
|
100
|
+
Carve comment, and an imported code block no longer gains a trailing blank
|
|
101
|
+
line on every pass (markup-carve/carve-rs#1361, markup-carve/carve-rs#1366,
|
|
102
|
+
markup-carve/carve-rs#1378, markup-carve/carve-rs#1386,
|
|
103
|
+
markup-carve/carve-rs#1384).
|
|
104
|
+
The third bump is 44 commits on its own, and rendered HTML moves on 50 corpus
|
|
105
|
+
documents with it. Measured against the corpus's own expected output at the
|
|
106
|
+
spec the new pin pins, the old pin differed on all 50 and the new pin on
|
|
107
|
+
none, so those 50 were being rendered wrongly and this is a correctness fix
|
|
108
|
+
rather than a preference. What an author notices is that a recognized block
|
|
109
|
+
opener written past a container's content column now opens that block inside
|
|
110
|
+
the container instead of folding into text: an indented `> q` under a list
|
|
111
|
+
item wrote `<p>> q</p>` and now writes a block quote, an indented `# h`
|
|
112
|
+
wrote `<p># h</p>` and now writes a heading, an indented code fence folded
|
|
113
|
+
into inline code inside a paragraph and now writes a `<pre>` block, and a
|
|
114
|
+
tab-indented `> quote` wrote text on the item's own line and now writes a
|
|
115
|
+
block quote; where a blank line preceded the block, the item is no longer
|
|
116
|
+
reported loose either. The same authored base applies inside a footnote body
|
|
117
|
+
and a definition description, so a table or a link reference definition
|
|
118
|
+
written past the body's column registers there (markup-carve/carve-rs#1387,
|
|
119
|
+
markup-carve/carve-rs#1420, markup-carve/carve-rs#1422,
|
|
120
|
+
markup-carve/carve-rs#1425, markup-carve/carve-rs#1431,
|
|
121
|
+
markup-carve/carve-rs#1432, markup-carve/carve-rs#1433, measured over the
|
|
122
|
+
corpus that markup-carve/carve-rs#1417 pins). Four further changes an
|
|
123
|
+
existing document can see ride along: an explicit id or class may begin with
|
|
124
|
+
an ASCII digit, so `::: 123` opens a div with that class instead of staying a
|
|
125
|
+
paragraph (markup-carve/carve-rs#1393); `::: >` spells a block quote with no
|
|
126
|
+
marker column, and its closing fence takes a caption
|
|
127
|
+
(markup-carve/carve-rs#1399, markup-carve/carve-rs#1411); reference and
|
|
128
|
+
footnote labels differing only in ASCII whitespace resolve to one definition
|
|
129
|
+
(markup-carve/carve-rs#1397); and `{align=left|right|center}` on an element
|
|
130
|
+
whose `align` means text alignment renders a CSS declaration rather than the
|
|
131
|
+
deprecated presentational attribute (markup-carve/carve-rs#1412).
|
|
132
|
+
`Carve.to_carve` also writes one space after a definition separator
|
|
133
|
+
(markup-carve/carve-rs#1426) (#98).
|
|
134
|
+
- The final release pin moves from `0c54d2ea` to the released carve-rs 0.1.4
|
|
135
|
+
(`2e9c43f2`). This closes every declared spec-drift window: link and
|
|
136
|
+
abbreviation definitions below a definition body's column follow the same
|
|
137
|
+
folding rule, a comment in a footnote body leaves no blank line behind, the
|
|
138
|
+
continuation marker's column gate reaches every container, an empty
|
|
139
|
+
description body writes the `{empty}` sentinel, citation items are typed and
|
|
140
|
+
positioned, and paragraph block-image promotion is published on the AST.
|
|
141
|
+
- The stale pin is what made this gem the only implementation failing PART 12
|
|
142
|
+
conformance in markup-carve/carve#1451 - a binding has no vote of its own, and
|
|
143
|
+
this one was voting with an engine 28 commits behind (#82). It recurred within
|
|
144
|
+
two days, on three documents and a pin one day old, because nothing in this
|
|
145
|
+
repository compares the tree this gem produces against the engine's own (#84).
|
|
146
|
+
It recurred again the next day, on one document, with that comparison still
|
|
147
|
+
unmerged (#86) and the pin 18 commits behind (#87). It recurred twice more
|
|
148
|
+
inside this window: at 39 commits behind, still carrying the PART 12 §4
|
|
149
|
+
extent defect (#89, #91), and again on a ruling only the tree can see,
|
|
150
|
+
which a byte-for-byte HTML comparison cannot detect (#93).
|
|
151
|
+
|
|
152
|
+
### Added
|
|
153
|
+
|
|
154
|
+
- `Carve.from_html(source, mode: :safe)` and `Carve.from_markdown(source)`
|
|
155
|
+
import an existing document into canonical Carve (#92). Both return the
|
|
156
|
+
shared migration shape `{value:, report:}`: `value` is the Carve source, and
|
|
157
|
+
`report` carries `diagnostics`, each with `code`, `message`, `severity` and,
|
|
158
|
+
where the engine placed one, `path`. `from_html` takes `:safe`, `:semantic`
|
|
159
|
+
or `:roundtrip` and reports back the `mode` and `adapter` it ran with; any
|
|
160
|
+
other mode raises `ArgumentError`. `from_markdown` reports
|
|
161
|
+
`source_format: "markdown"` and diagnoses nothing.
|
|
162
|
+
- `Carve.to_markdown`, `to_plain_text`, `to_ansi` and `to_carve`, so every core
|
|
163
|
+
render target the embedded engine already understood is reachable from Ruby
|
|
164
|
+
(#88). `Carve.to_html` and the AST entry points are unchanged.
|
|
165
|
+
|
|
10
166
|
## [0.1.1] - 2026-08-18
|
|
11
167
|
|
|
12
168
|
Everything below is the delta from `v0.1.0`, which is the only version a
|
|
@@ -168,6 +324,8 @@ are not listed, because no release ever shipped them.
|
|
|
168
324
|
Arrays (every AST node type is covered), enabling custom renderers such as
|
|
169
325
|
[carve-hexapdf](https://github.com/markup-carve/carve-hexapdf).
|
|
170
326
|
|
|
171
|
-
[Unreleased]: https://github.com/markup-carve/carve-rb/compare/v0.1.
|
|
327
|
+
[Unreleased]: https://github.com/markup-carve/carve-rb/compare/v0.1.3...HEAD
|
|
328
|
+
[0.1.3]: https://github.com/markup-carve/carve-rb/compare/v0.1.2...v0.1.3
|
|
329
|
+
[0.1.2]: https://github.com/markup-carve/carve-rb/compare/v0.1.1...v0.1.2
|
|
172
330
|
[0.1.1]: https://github.com/markup-carve/carve-rb/compare/v0.1.0...v0.1.1
|
|
173
331
|
[0.1.0]: https://github.com/markup-carve/carve-rb/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -37,6 +37,14 @@ time via `rb_sys`.
|
|
|
37
37
|
require "carve"
|
|
38
38
|
|
|
39
39
|
Carve.to_html("# Hello *world*")
|
|
40
|
+
|
|
41
|
+
# Every core engine target is available from the binding.
|
|
42
|
+
Carve.to_markdown(source)
|
|
43
|
+
Carve.to_plain_text(source)
|
|
44
|
+
Carve.to_ansi(source)
|
|
45
|
+
Carve.to_carve(source)
|
|
46
|
+
Carve.from_html('<p>Hello <strong>world</strong></p>')
|
|
47
|
+
Carve.from_markdown('*em* and **strong**')
|
|
40
48
|
# => "<section id=\"Hello-world\">\n <h1>Hello <strong>world</strong></h1>\n</section>"
|
|
41
49
|
|
|
42
50
|
# Carve syntax note: *...* is STRONG (bold), /.../ is EMPHASIS (italic).
|
|
@@ -320,7 +328,3 @@ that has fallen behind fails a build. Locally:
|
|
|
320
328
|
```sh
|
|
321
329
|
CARVE_SPEC_CORPUS=/path/to/carve/tests/corpus bundle exec rake test
|
|
322
330
|
```
|
|
323
|
-
|
|
324
|
-
## License
|
|
325
|
-
|
|
326
|
-
MIT, markup-carve.
|
data/ext/carve/Cargo.lock
CHANGED
|
@@ -37,21 +37,26 @@ checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
|
|
37
37
|
|
|
38
38
|
[[package]]
|
|
39
39
|
name = "carve-lang"
|
|
40
|
-
version = "0.1.
|
|
41
|
-
source = "git+https://github.com/markup-carve/carve-rs?rev=
|
|
40
|
+
version = "0.1.4"
|
|
41
|
+
source = "git+https://github.com/markup-carve/carve-rs?rev=42df409227dc260cec336a6569f4f41c712cdc22#42df409227dc260cec336a6569f4f41c712cdc22"
|
|
42
42
|
dependencies = [
|
|
43
43
|
"html5ever",
|
|
44
44
|
"markup5ever_rcdom",
|
|
45
45
|
"pulldown-cmark",
|
|
46
|
+
"regex",
|
|
47
|
+
"serde",
|
|
48
|
+
"serde_json",
|
|
49
|
+
"unicode-normalization",
|
|
46
50
|
]
|
|
47
51
|
|
|
48
52
|
[[package]]
|
|
49
53
|
name = "carve-rb"
|
|
50
|
-
version = "0.1.
|
|
54
|
+
version = "0.1.3"
|
|
51
55
|
dependencies = [
|
|
52
56
|
"carve-lang",
|
|
53
57
|
"magnus",
|
|
54
58
|
"rb-sys",
|
|
59
|
+
"serde_json",
|
|
55
60
|
]
|
|
56
61
|
|
|
57
62
|
[[package]]
|
|
@@ -87,14 +92,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
87
92
|
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
|
88
93
|
|
|
89
94
|
[[package]]
|
|
90
|
-
name = "
|
|
91
|
-
version = "
|
|
95
|
+
name = "fastrand"
|
|
96
|
+
version = "2.5.0"
|
|
92
97
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
93
|
-
checksum = "
|
|
94
|
-
dependencies = [
|
|
95
|
-
"mac",
|
|
96
|
-
"new_debug_unreachable",
|
|
97
|
-
]
|
|
98
|
+
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
|
98
99
|
|
|
99
100
|
[[package]]
|
|
100
101
|
name = "glob"
|
|
@@ -104,16 +105,12 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
|
|
104
105
|
|
|
105
106
|
[[package]]
|
|
106
107
|
name = "html5ever"
|
|
107
|
-
version = "0.
|
|
108
|
+
version = "0.39.0"
|
|
108
109
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
109
|
-
checksum = "
|
|
110
|
+
checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8"
|
|
110
111
|
dependencies = [
|
|
111
112
|
"log",
|
|
112
|
-
"mac",
|
|
113
113
|
"markup5ever",
|
|
114
|
-
"proc-macro2",
|
|
115
|
-
"quote",
|
|
116
|
-
"syn 2.0.118",
|
|
117
114
|
]
|
|
118
115
|
|
|
119
116
|
[[package]]
|
|
@@ -125,6 +122,12 @@ dependencies = [
|
|
|
125
122
|
"either",
|
|
126
123
|
]
|
|
127
124
|
|
|
125
|
+
[[package]]
|
|
126
|
+
name = "itoa"
|
|
127
|
+
version = "1.0.18"
|
|
128
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
129
|
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
130
|
+
|
|
128
131
|
[[package]]
|
|
129
132
|
name = "lazy_static"
|
|
130
133
|
version = "1.5.0"
|
|
@@ -162,12 +165,6 @@ version = "0.4.33"
|
|
|
162
165
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
163
166
|
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
|
164
167
|
|
|
165
|
-
[[package]]
|
|
166
|
-
name = "mac"
|
|
167
|
-
version = "0.1.1"
|
|
168
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
169
|
-
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
|
170
|
-
|
|
171
168
|
[[package]]
|
|
172
169
|
name = "magnus"
|
|
173
170
|
version = "0.8.2"
|
|
@@ -193,23 +190,20 @@ dependencies = [
|
|
|
193
190
|
|
|
194
191
|
[[package]]
|
|
195
192
|
name = "markup5ever"
|
|
196
|
-
version = "0.
|
|
193
|
+
version = "0.39.0"
|
|
197
194
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
198
|
-
checksum = "
|
|
195
|
+
checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de"
|
|
199
196
|
dependencies = [
|
|
200
197
|
"log",
|
|
201
|
-
"phf",
|
|
202
|
-
"phf_codegen",
|
|
203
|
-
"string_cache",
|
|
204
|
-
"string_cache_codegen",
|
|
205
198
|
"tendril",
|
|
199
|
+
"web_atoms",
|
|
206
200
|
]
|
|
207
201
|
|
|
208
202
|
[[package]]
|
|
209
203
|
name = "markup5ever_rcdom"
|
|
210
|
-
version = "0.
|
|
204
|
+
version = "0.39.0+unofficial"
|
|
211
205
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
212
|
-
checksum = "
|
|
206
|
+
checksum = "3ac010f19d6c4af81eeb4018a39d7a115de9d285af45c126a4ac02e6fc5716b7"
|
|
213
207
|
dependencies = [
|
|
214
208
|
"html5ever",
|
|
215
209
|
"markup5ever",
|
|
@@ -270,18 +264,19 @@ dependencies = [
|
|
|
270
264
|
|
|
271
265
|
[[package]]
|
|
272
266
|
name = "phf"
|
|
273
|
-
version = "0.
|
|
267
|
+
version = "0.13.1"
|
|
274
268
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
275
|
-
checksum = "
|
|
269
|
+
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
|
|
276
270
|
dependencies = [
|
|
277
271
|
"phf_shared",
|
|
272
|
+
"serde",
|
|
278
273
|
]
|
|
279
274
|
|
|
280
275
|
[[package]]
|
|
281
276
|
name = "phf_codegen"
|
|
282
|
-
version = "0.
|
|
277
|
+
version = "0.13.1"
|
|
283
278
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
284
|
-
checksum = "
|
|
279
|
+
checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
|
|
285
280
|
dependencies = [
|
|
286
281
|
"phf_generator",
|
|
287
282
|
"phf_shared",
|
|
@@ -289,19 +284,19 @@ dependencies = [
|
|
|
289
284
|
|
|
290
285
|
[[package]]
|
|
291
286
|
name = "phf_generator"
|
|
292
|
-
version = "0.
|
|
287
|
+
version = "0.13.1"
|
|
293
288
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
294
|
-
checksum = "
|
|
289
|
+
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
|
|
295
290
|
dependencies = [
|
|
291
|
+
"fastrand",
|
|
296
292
|
"phf_shared",
|
|
297
|
-
"rand",
|
|
298
293
|
]
|
|
299
294
|
|
|
300
295
|
[[package]]
|
|
301
296
|
name = "phf_shared"
|
|
302
|
-
version = "0.
|
|
297
|
+
version = "0.13.1"
|
|
303
298
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
304
|
-
checksum = "
|
|
299
|
+
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
|
|
305
300
|
dependencies = [
|
|
306
301
|
"siphasher",
|
|
307
302
|
]
|
|
@@ -341,21 +336,6 @@ dependencies = [
|
|
|
341
336
|
"proc-macro2",
|
|
342
337
|
]
|
|
343
338
|
|
|
344
|
-
[[package]]
|
|
345
|
-
name = "rand"
|
|
346
|
-
version = "0.8.7"
|
|
347
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
348
|
-
checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a"
|
|
349
|
-
dependencies = [
|
|
350
|
-
"rand_core",
|
|
351
|
-
]
|
|
352
|
-
|
|
353
|
-
[[package]]
|
|
354
|
-
name = "rand_core"
|
|
355
|
-
version = "0.6.4"
|
|
356
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
357
|
-
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
358
|
-
|
|
359
339
|
[[package]]
|
|
360
340
|
name = "rb-sys"
|
|
361
341
|
version = "0.9.128"
|
|
@@ -449,6 +429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
449
429
|
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
|
450
430
|
dependencies = [
|
|
451
431
|
"serde_core",
|
|
432
|
+
"serde_derive",
|
|
452
433
|
]
|
|
453
434
|
|
|
454
435
|
[[package]]
|
|
@@ -471,6 +452,19 @@ dependencies = [
|
|
|
471
452
|
"syn 3.0.3",
|
|
472
453
|
]
|
|
473
454
|
|
|
455
|
+
[[package]]
|
|
456
|
+
name = "serde_json"
|
|
457
|
+
version = "1.0.151"
|
|
458
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
459
|
+
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
|
460
|
+
dependencies = [
|
|
461
|
+
"itoa",
|
|
462
|
+
"memchr",
|
|
463
|
+
"serde",
|
|
464
|
+
"serde_core",
|
|
465
|
+
"zmij",
|
|
466
|
+
]
|
|
467
|
+
|
|
474
468
|
[[package]]
|
|
475
469
|
name = "shell-words"
|
|
476
470
|
version = "1.1.1"
|
|
@@ -497,9 +491,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
|
|
497
491
|
|
|
498
492
|
[[package]]
|
|
499
493
|
name = "string_cache"
|
|
500
|
-
version = "0.
|
|
494
|
+
version = "0.9.0"
|
|
501
495
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
502
|
-
checksum = "
|
|
496
|
+
checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901"
|
|
503
497
|
dependencies = [
|
|
504
498
|
"new_debug_unreachable",
|
|
505
499
|
"parking_lot",
|
|
@@ -510,9 +504,9 @@ dependencies = [
|
|
|
510
504
|
|
|
511
505
|
[[package]]
|
|
512
506
|
name = "string_cache_codegen"
|
|
513
|
-
version = "0.
|
|
507
|
+
version = "0.6.1"
|
|
514
508
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
515
|
-
checksum = "
|
|
509
|
+
checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69"
|
|
516
510
|
dependencies = [
|
|
517
511
|
"phf_generator",
|
|
518
512
|
"phf_shared",
|
|
@@ -544,15 +538,28 @@ dependencies = [
|
|
|
544
538
|
|
|
545
539
|
[[package]]
|
|
546
540
|
name = "tendril"
|
|
547
|
-
version = "0.
|
|
541
|
+
version = "0.5.1"
|
|
548
542
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
549
|
-
checksum = "
|
|
543
|
+
checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08"
|
|
550
544
|
dependencies = [
|
|
551
|
-
"
|
|
552
|
-
|
|
553
|
-
|
|
545
|
+
"new_debug_unreachable",
|
|
546
|
+
]
|
|
547
|
+
|
|
548
|
+
[[package]]
|
|
549
|
+
name = "tinyvec"
|
|
550
|
+
version = "1.12.0"
|
|
551
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
552
|
+
checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f"
|
|
553
|
+
dependencies = [
|
|
554
|
+
"tinyvec_macros",
|
|
554
555
|
]
|
|
555
556
|
|
|
557
|
+
[[package]]
|
|
558
|
+
name = "tinyvec_macros"
|
|
559
|
+
version = "0.1.1"
|
|
560
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
561
|
+
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|
562
|
+
|
|
556
563
|
[[package]]
|
|
557
564
|
name = "unicase"
|
|
558
565
|
version = "2.9.0"
|
|
@@ -566,10 +573,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
566
573
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
567
574
|
|
|
568
575
|
[[package]]
|
|
569
|
-
name = "
|
|
570
|
-
version = "0.
|
|
576
|
+
name = "unicode-normalization"
|
|
577
|
+
version = "0.1.25"
|
|
578
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
579
|
+
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
|
|
580
|
+
dependencies = [
|
|
581
|
+
"tinyvec",
|
|
582
|
+
]
|
|
583
|
+
|
|
584
|
+
[[package]]
|
|
585
|
+
name = "web_atoms"
|
|
586
|
+
version = "0.2.6"
|
|
571
587
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
572
|
-
checksum = "
|
|
588
|
+
checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3"
|
|
589
|
+
dependencies = [
|
|
590
|
+
"phf",
|
|
591
|
+
"phf_codegen",
|
|
592
|
+
"string_cache",
|
|
593
|
+
"string_cache_codegen",
|
|
594
|
+
]
|
|
573
595
|
|
|
574
596
|
[[package]]
|
|
575
597
|
name = "windows-link"
|
|
@@ -579,11 +601,16 @@ checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
|
|
579
601
|
|
|
580
602
|
[[package]]
|
|
581
603
|
name = "xml5ever"
|
|
582
|
-
version = "0.
|
|
604
|
+
version = "0.39.0"
|
|
583
605
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
584
|
-
checksum = "
|
|
606
|
+
checksum = "5ab627f34ff61b80d756180d556f9c68801d836d271b3b8c094504ceca69d221"
|
|
585
607
|
dependencies = [
|
|
586
608
|
"log",
|
|
587
|
-
"mac",
|
|
588
609
|
"markup5ever",
|
|
589
610
|
]
|
|
611
|
+
|
|
612
|
+
[[package]]
|
|
613
|
+
name = "zmij"
|
|
614
|
+
version = "1.0.23"
|
|
615
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
616
|
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
data/ext/carve/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "carve-rb"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
rust-version = "1.75"
|
|
6
6
|
publish = false
|
|
@@ -17,8 +17,9 @@ crate-type = ["cdylib"]
|
|
|
17
17
|
# interop handles so this builds cleanly under rb_sys/mkmf for Ruby 3.2.
|
|
18
18
|
magnus = { version = "0.8", features = ["rb-sys"] }
|
|
19
19
|
rb-sys = "0.9"
|
|
20
|
+
serde_json = "1"
|
|
20
21
|
|
|
21
22
|
# The Carve engine. Imported under the Rust crate alias `carve_rs` so the
|
|
22
23
|
# binding's own crate name (`carve-rb`) does not collide with the engine's
|
|
23
24
|
# package name (`carve`) in the Cargo lockfile.
|
|
24
|
-
carve_rs = { package = "carve-lang", git = "https://github.com/markup-carve/carve-rs", rev = "
|
|
25
|
+
carve_rs = { package = "carve-lang", git = "https://github.com/markup-carve/carve-rs", rev = "42df409227dc260cec336a6569f4f41c712cdc22" }
|
data/ext/carve/src/lib.rs
CHANGED
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
//! symbols: {...}, safe: ..., profile: ..., sections: ...)` on top of these
|
|
25
25
|
//! primitives.
|
|
26
26
|
|
|
27
|
-
|
|
28
27
|
use carve_rs::extensions::registry;
|
|
29
28
|
use carve_rs::{CarveExtension, Mode, Options, Profile, StaticRenderers};
|
|
30
29
|
use magnus::value::{InnerValue, Opaque};
|
|
@@ -200,6 +199,73 @@ fn to_html(source: String) -> String {
|
|
|
200
199
|
carve_rs::to_html(&source)
|
|
201
200
|
}
|
|
202
201
|
|
|
202
|
+
fn to_markdown(source: String) -> String {
|
|
203
|
+
carve_rs::to_markdown(&source)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fn to_plain_text(source: String) -> String {
|
|
207
|
+
carve_rs::to_plain_text(&source)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fn to_ansi(source: String) -> String {
|
|
211
|
+
carve_rs::to_ansi(&source)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fn to_carve(source: String) -> String {
|
|
215
|
+
carve_rs::to_carve(&source)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fn from_html_json(ruby: &Ruby, source: String, mode: String) -> Result<String, Error> {
|
|
219
|
+
let mode = carve_rs::HtmlImportMode::from_name(&mode).ok_or_else(|| {
|
|
220
|
+
Error::new(
|
|
221
|
+
ruby.exception_arg_error(),
|
|
222
|
+
"mode must be safe, semantic, or roundtrip".to_string(),
|
|
223
|
+
)
|
|
224
|
+
})?;
|
|
225
|
+
let result = carve_rs::html_to_carve(
|
|
226
|
+
&source,
|
|
227
|
+
&carve_rs::HtmlImportOptions {
|
|
228
|
+
mode,
|
|
229
|
+
..Default::default()
|
|
230
|
+
},
|
|
231
|
+
)
|
|
232
|
+
.map_err(|error| {
|
|
233
|
+
Error::new(
|
|
234
|
+
ruby.exception_runtime_error(),
|
|
235
|
+
format!("HTML import failed: {error:?}"),
|
|
236
|
+
)
|
|
237
|
+
})?;
|
|
238
|
+
let diagnostics = result
|
|
239
|
+
.report
|
|
240
|
+
.diagnostics
|
|
241
|
+
.iter()
|
|
242
|
+
.map(|diagnostic| {
|
|
243
|
+
let mut value = serde_json::json!({
|
|
244
|
+
"code": diagnostic.code.as_str(),
|
|
245
|
+
"message": diagnostic.message,
|
|
246
|
+
"severity": diagnostic.severity.as_str(),
|
|
247
|
+
});
|
|
248
|
+
if let Some(path) = &diagnostic.path {
|
|
249
|
+
value["path"] = serde_json::json!(path);
|
|
250
|
+
}
|
|
251
|
+
value
|
|
252
|
+
})
|
|
253
|
+
.collect::<Vec<_>>();
|
|
254
|
+
Ok(serde_json::json!({
|
|
255
|
+
"value": result.value,
|
|
256
|
+
"report": {
|
|
257
|
+
"mode": result.report.mode.as_str(),
|
|
258
|
+
"adapter": result.report.adapter.as_str(),
|
|
259
|
+
"diagnostics": diagnostics,
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
.to_string())
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fn from_markdown(source: String) -> String {
|
|
266
|
+
carve_rs::markdown_to_carve(&source)
|
|
267
|
+
}
|
|
268
|
+
|
|
203
269
|
/// Parse Carve source and return its AST as a JSON string.
|
|
204
270
|
///
|
|
205
271
|
/// The pure-Ruby wrapper (`Carve.parse`) turns this into a tree of Ruby
|
|
@@ -319,7 +385,9 @@ fn to_html_full_with_symbols(
|
|
|
319
385
|
// The safe-render arguments default off and section wrapping stays on, so
|
|
320
386
|
// this signature stays as published; `to_html_safe` is the one that takes
|
|
321
387
|
// them.
|
|
322
|
-
to_html_safe(
|
|
388
|
+
to_html_safe(
|
|
389
|
+
ruby, source, names, mode, renderers, symbols, false, None, true,
|
|
390
|
+
)
|
|
323
391
|
}
|
|
324
392
|
|
|
325
393
|
/// Map a profile name to a [`Profile`], or raise Ruby ArgumentError.
|
|
@@ -407,7 +475,6 @@ fn to_html_safe(
|
|
|
407
475
|
.map_err(|e| Error::new(ruby.exception_arg_error(), e.to_string()))
|
|
408
476
|
}
|
|
409
477
|
|
|
410
|
-
|
|
411
478
|
/// Read a document's provenance marker.
|
|
412
479
|
///
|
|
413
480
|
/// Returns a Hash `{version:, generated_by:}` or nil when the document carries
|
|
@@ -452,6 +519,12 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
|
452
519
|
// these. `_to_html` is the no-extension fast path; the wrapper owns the
|
|
453
520
|
// bare `to_html` name.
|
|
454
521
|
module.define_singleton_method("_to_html", function!(to_html, 1))?;
|
|
522
|
+
module.define_singleton_method("to_markdown", function!(to_markdown, 1))?;
|
|
523
|
+
module.define_singleton_method("to_plain_text", function!(to_plain_text, 1))?;
|
|
524
|
+
module.define_singleton_method("to_ansi", function!(to_ansi, 1))?;
|
|
525
|
+
module.define_singleton_method("to_carve", function!(to_carve, 1))?;
|
|
526
|
+
module.define_singleton_method("_from_html_json", function!(from_html_json, 2))?;
|
|
527
|
+
module.define_singleton_method("_from_markdown", function!(from_markdown, 1))?;
|
|
455
528
|
module.define_singleton_method("_to_ast_json", function!(to_ast_json, 1))?;
|
|
456
529
|
module.define_singleton_method(
|
|
457
530
|
"to_html_with_extensions",
|
data/lib/carve/version.rb
CHANGED
|
@@ -8,5 +8,5 @@ module Carve
|
|
|
8
8
|
# compares it against ext/carve/Cargo.toml and against the newest cut
|
|
9
9
|
# CHANGELOG section on every run, and .github/workflows/release.yml refuses to
|
|
10
10
|
# publish a gem whose version is not the tag being released.
|
|
11
|
-
VERSION = "0.1.
|
|
11
|
+
VERSION = "0.1.3"
|
|
12
12
|
end
|
data/lib/carve.rb
CHANGED
|
@@ -42,6 +42,19 @@ module Carve
|
|
|
42
42
|
RENDERER_KEYS = %i[mermaid chart graphviz math].freeze
|
|
43
43
|
|
|
44
44
|
class << self
|
|
45
|
+
# Import HTML or Markdown into canonical Carve. Both methods return the
|
|
46
|
+
# shared migration shape `{ value:, report: }`.
|
|
47
|
+
def from_html(source, mode: :safe)
|
|
48
|
+
JSON.parse(_from_html_json(source, mode.to_s), symbolize_names: true)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def from_markdown(source)
|
|
52
|
+
{
|
|
53
|
+
value: _from_markdown(source),
|
|
54
|
+
report: { source_format: "markdown", diagnostics: [] }
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
45
58
|
# Render Carve +source+ to an HTML string.
|
|
46
59
|
#
|
|
47
60
|
# With no extensions:
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: carve-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- markup-carve
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08
|
|
11
|
+
date: 2026-09-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rb_sys
|
|
@@ -88,7 +88,8 @@ files:
|
|
|
88
88
|
homepage: https://github.com/markup-carve/carve-rb
|
|
89
89
|
licenses:
|
|
90
90
|
- MIT
|
|
91
|
-
metadata:
|
|
91
|
+
metadata:
|
|
92
|
+
rubygems_mfa_required: 'true'
|
|
92
93
|
post_install_message:
|
|
93
94
|
rdoc_options: []
|
|
94
95
|
require_paths:
|