slamdown 0.5.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 +7 -0
- data/changelog.md +7 -0
- data/lib/slamdown/conversion/configuration.rb +35 -0
- data/lib/slamdown/conversion/configuration_validator.rb +235 -0
- data/lib/slamdown/conversion/converter.rb +98 -0
- data/lib/slamdown/conversion/normalisation.rb +21 -0
- data/lib/slamdown/conversion/normalised_node.rb +40 -0
- data/lib/slamdown/conversion/normaliser/breaks.rb +104 -0
- data/lib/slamdown/conversion/normaliser/content.rb +174 -0
- data/lib/slamdown/conversion/normaliser/correction_diagnostics.rb +29 -0
- data/lib/slamdown/conversion/normaliser/element_actions.rb +423 -0
- data/lib/slamdown/conversion/normaliser/heading_levels.rb +45 -0
- data/lib/slamdown/conversion/normaliser/inline_semantics.rb +218 -0
- data/lib/slamdown/conversion/normaliser/node_factory.rb +112 -0
- data/lib/slamdown/conversion/normaliser/url_rewriter.rb +124 -0
- data/lib/slamdown/conversion/normaliser.rb +58 -0
- data/lib/slamdown/conversion/policy.rb +178 -0
- data/lib/slamdown/conversion/prepared_node.rb +23 -0
- data/lib/slamdown/conversion/preparer.rb +122 -0
- data/lib/slamdown/conversion/renderer.rb +432 -0
- data/lib/slamdown/conversion/rendering/entity_encoder.rb +56 -0
- data/lib/slamdown/conversion/rendering/escaper.rb +58 -0
- data/lib/slamdown/conversion/rendering/html.rb +183 -0
- data/lib/slamdown/conversion/rendering/result.rb +23 -0
- data/lib/slamdown/conversion/rendering/strategy.rb +157 -0
- data/lib/slamdown/conversion/semantic_extractor.rb +97 -0
- data/lib/slamdown/conversion/tables.rb +676 -0
- data/lib/slamdown/conversion.rb +34 -0
- data/lib/slamdown/diagnostic.rb +34 -0
- data/lib/slamdown/document.rb +107 -0
- data/lib/slamdown/errors.rb +25 -0
- data/lib/slamdown/immutable.rb +23 -0
- data/lib/slamdown/output.rb +30 -0
- data/lib/slamdown/parsing/html.rb +227 -0
- data/lib/slamdown/parsing/node.rb +50 -0
- data/lib/slamdown/parsing/parsed_node_adapter.rb +144 -0
- data/lib/slamdown/parsing.rb +17 -0
- data/lib/slamdown/version.rb +3 -0
- data/lib/slamdown.rb +10 -0
- data/readme.md +121 -0
- metadata +174 -0
data/readme.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Slamdown (Ruby Gem)
|
|
2
|
+
|
|
3
|
+
**Converts potentially-messy HTML to clean Markdown using opinionated, configurable processing rules.**
|
|
4
|
+
|
|
5
|
+
When an HTML representation of content has been authored poorly, resulting in messy or unsemantic HTML, Slamdown can reduce it to Markdown or Kramdown that reflects editor intent. The processing is opinionated and lossy, with a no-configuration default that suits most situations.
|
|
6
|
+
|
|
7
|
+
The primary use-case for Slamdown is processing HTML that has been authored in a WYSIWYG editor. These can often accumulate invisible HTML chaos: nested `div`s or `br` instead of `p`, wacky attributes, `i` instead of `em`, etc. A cleaned Markdown/Kramdown representation of this is particularly useful when this content must be used by an SSG like Jekyll.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## Convert HTML
|
|
11
|
+
|
|
12
|
+
Create a document from HTML and render it as Markdown or Kramdown:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
require "slamdown"
|
|
16
|
+
|
|
17
|
+
document = Slamdown::Document.new("<div><h2>Welcome</h2><p>A <b>cleaner</b> document.</p></div>")
|
|
18
|
+
|
|
19
|
+
document.to_markdown
|
|
20
|
+
# => "# Welcome\n\nA **cleaner** document."
|
|
21
|
+
|
|
22
|
+
document.to_kramdown
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Slamdown cleans common editor output as it converts it. It recognises paragraphs, headings, blockquotes, ordered and unordered lists, definition lists, horizontal rules, links, images, emphasis, strong text, strikethrough, inline and fenced code, and tables. It also recovers semantic emphasis from styled spans where possible, removes comments and processing instructions, normalises whitespace, and drops unsafe link schemes.
|
|
26
|
+
|
|
27
|
+
Use the full conversion API when you need the output type and conversion diagnostics:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
result = Slamdown::Document.convert(document, format: :markdown)
|
|
31
|
+
|
|
32
|
+
result.output
|
|
33
|
+
result.diagnostics
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Options
|
|
38
|
+
|
|
39
|
+
Pass conversion options as the first argument to `to_markdown` or `to_kramdown`, or as `options:` to `Document.convert`.
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
document.to_markdown(headings: {start: 1}, entities: :numeric)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Option | Default | Use it to |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| `inline` | `false` | Produce inline-friendly output: block elements are flattened and code whitespace is collapsed. |
|
|
48
|
+
| `headings: {start:, compact:}` | `start: 2`, `compact: true` | Set the first heading level (`1`-`6`); compact source heading levels so gaps are removed, or retain their spacing with `compact: false`. |
|
|
49
|
+
| `entities` | `:character` | Render entities as Unicode characters, named entities (`:symbolic`), or numeric entities (`:numeric`). |
|
|
50
|
+
| `html_indent` | `"\t"` | Choose indentation for HTML preserved in the output: `""`, one tab, or one to eight spaces. |
|
|
51
|
+
| `urls: {scheme:, host:, path:, force:}` | `force: :relative` | Rewrite matching link and image URLs. Supply a site scheme, host and/or path; use `force: :relative` for site-relative URLs or `:absolute` (requires scheme and host) for absolute URLs. |
|
|
52
|
+
| `tables: {format:, max_width:}` | `format: :auto`, `max_width: 150` | Use native pipe tables where possible, or `format: :html` to always retain tables as HTML. Set `max_width` to an integer of at least 20, or `nil`, to control pipe-table width before falling back to HTML. |
|
|
53
|
+
| `elements` | `{}` | Change how particular HTML elements are handled and which non-class/id attributes survive. |
|
|
54
|
+
| `classes` | `{}` | Retain matching class names, by element. |
|
|
55
|
+
| `ids` | `{}` | Retain matching IDs, by element. |
|
|
56
|
+
|
|
57
|
+
The URL options preserve external URLs and query strings/fragments. For example:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
document.to_markdown(urls: {scheme: "https", host: "example.com", path: "news", force: :absolute})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## Keep or change HTML
|
|
65
|
+
|
|
66
|
+
By default, Slamdown converts standard structural elements and keeps a small set of semantic HTML elements such as `abbr`, `cite`, `del`, `ins`, `mark`, `sub`, `sup` and `u`. Other unknown elements are unwrapped when they contain useful content, or dropped when they do not. Attributes are dropped unless they are needed by a recognised feature (such as `href`, `src`, `alt`, table spans, or an ordered-list start).
|
|
67
|
+
|
|
68
|
+
Use `elements` to override this policy. Available actions are:
|
|
69
|
+
|
|
70
|
+
* `:convert` - convert an element using Slamdown's native rule (only for supported elements).
|
|
71
|
+
* `:preserve` - keep the element as HTML.
|
|
72
|
+
* `:unwrap` - remove the element but keep its contents.
|
|
73
|
+
* `:inline` - keep its contents while flattening block structure.
|
|
74
|
+
* `:drop` - remove the element and its contents.
|
|
75
|
+
|
|
76
|
+
For example, preserve a `figure` and its `data-*` attribute, while removing all `style` attributes:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
options = {
|
|
80
|
+
elements: {
|
|
81
|
+
figure: {action: :preserve, attributes: {"data-caption": :preserve}},
|
|
82
|
+
any: {attributes: {style: :drop}}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
document.to_markdown(options)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Attribute actions are `:preserve` and `:drop`. Use `any` as an element or attribute name to create a catch-all rule; an element-specific rule takes precedence.
|
|
90
|
+
|
|
91
|
+
Retain only the classes or IDs your output needs. Matchers can be exact strings, regular expressions, arrays of either, or `:any`:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
document.to_kramdown(
|
|
95
|
+
classes: {code: [/\Alanguage-/], table: :any},
|
|
96
|
+
ids: {h2: ["installation", "usage"]}
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## Errors and diagnostics
|
|
102
|
+
|
|
103
|
+
Parsing and conversion errors warn to standard error by default and return an empty or partial result where possible. Choose the behaviour with `errors: :warn` (default), `:silent`, or `:raise`:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
document = Slamdown::Document.new(html, errors: :raise)
|
|
107
|
+
result = Slamdown::Document.convert(document, format: :markdown, errors: :raise)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`Document#diagnostics` reports parsing observations. `result.diagnostics` reports conversion observations too, such as adjusted heading levels, removed blank headings, table fallbacks, and recovered editor formatting.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
## Installation
|
|
114
|
+
|
|
115
|
+
Add Slamdown to your Gemfile:
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
gem "slamdown"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Then run `bundle install`.
|
metadata
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: slamdown
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.5.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Convincible Media
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-08-18 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: kramdown
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.1'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '12.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '12.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: pry
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0.12'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0.12'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: pry-byebug
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.6'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '3.6'
|
|
97
|
+
description: Converts potentially-messy HTML to clean Markdown using opinionated,
|
|
98
|
+
configurable processing rules. Useful for working with HTML that has been authored
|
|
99
|
+
in a WYSIWYG editor.
|
|
100
|
+
email:
|
|
101
|
+
- development@convincible.media
|
|
102
|
+
executables: []
|
|
103
|
+
extensions: []
|
|
104
|
+
extra_rdoc_files: []
|
|
105
|
+
files:
|
|
106
|
+
- changelog.md
|
|
107
|
+
- lib/slamdown.rb
|
|
108
|
+
- lib/slamdown/conversion.rb
|
|
109
|
+
- lib/slamdown/conversion/configuration.rb
|
|
110
|
+
- lib/slamdown/conversion/configuration_validator.rb
|
|
111
|
+
- lib/slamdown/conversion/converter.rb
|
|
112
|
+
- lib/slamdown/conversion/normalisation.rb
|
|
113
|
+
- lib/slamdown/conversion/normalised_node.rb
|
|
114
|
+
- lib/slamdown/conversion/normaliser.rb
|
|
115
|
+
- lib/slamdown/conversion/normaliser/breaks.rb
|
|
116
|
+
- lib/slamdown/conversion/normaliser/content.rb
|
|
117
|
+
- lib/slamdown/conversion/normaliser/correction_diagnostics.rb
|
|
118
|
+
- lib/slamdown/conversion/normaliser/element_actions.rb
|
|
119
|
+
- lib/slamdown/conversion/normaliser/heading_levels.rb
|
|
120
|
+
- lib/slamdown/conversion/normaliser/inline_semantics.rb
|
|
121
|
+
- lib/slamdown/conversion/normaliser/node_factory.rb
|
|
122
|
+
- lib/slamdown/conversion/normaliser/url_rewriter.rb
|
|
123
|
+
- lib/slamdown/conversion/policy.rb
|
|
124
|
+
- lib/slamdown/conversion/prepared_node.rb
|
|
125
|
+
- lib/slamdown/conversion/preparer.rb
|
|
126
|
+
- lib/slamdown/conversion/renderer.rb
|
|
127
|
+
- lib/slamdown/conversion/rendering/entity_encoder.rb
|
|
128
|
+
- lib/slamdown/conversion/rendering/escaper.rb
|
|
129
|
+
- lib/slamdown/conversion/rendering/html.rb
|
|
130
|
+
- lib/slamdown/conversion/rendering/result.rb
|
|
131
|
+
- lib/slamdown/conversion/rendering/strategy.rb
|
|
132
|
+
- lib/slamdown/conversion/semantic_extractor.rb
|
|
133
|
+
- lib/slamdown/conversion/tables.rb
|
|
134
|
+
- lib/slamdown/diagnostic.rb
|
|
135
|
+
- lib/slamdown/document.rb
|
|
136
|
+
- lib/slamdown/errors.rb
|
|
137
|
+
- lib/slamdown/immutable.rb
|
|
138
|
+
- lib/slamdown/output.rb
|
|
139
|
+
- lib/slamdown/parsing.rb
|
|
140
|
+
- lib/slamdown/parsing/html.rb
|
|
141
|
+
- lib/slamdown/parsing/node.rb
|
|
142
|
+
- lib/slamdown/parsing/parsed_node_adapter.rb
|
|
143
|
+
- lib/slamdown/version.rb
|
|
144
|
+
- readme.md
|
|
145
|
+
homepage: https://github.com/ConvincibleMedia/ruby-gem-slamdown
|
|
146
|
+
licenses:
|
|
147
|
+
- LGPL-3.0-or-later
|
|
148
|
+
metadata:
|
|
149
|
+
bug_tracker_uri: https://github.com/ConvincibleMedia/ruby-gem-slamdown/issues
|
|
150
|
+
changelog_uri: https://github.com/ConvincibleMedia/ruby-gem-slamdown/blob/master/changelog.md
|
|
151
|
+
homepage_uri: https://github.com/ConvincibleMedia/ruby-gem-slamdown
|
|
152
|
+
source_code_uri: https://github.com/ConvincibleMedia/ruby-gem-slamdown/tree/v0.5.0
|
|
153
|
+
rubygems_mfa_required: 'true'
|
|
154
|
+
post_install_message:
|
|
155
|
+
rdoc_options: []
|
|
156
|
+
require_paths:
|
|
157
|
+
- lib
|
|
158
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
|
+
requirements:
|
|
160
|
+
- - ">="
|
|
161
|
+
- !ruby/object:Gem::Version
|
|
162
|
+
version: '2.3'
|
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
|
+
requirements:
|
|
165
|
+
- - ">="
|
|
166
|
+
- !ruby/object:Gem::Version
|
|
167
|
+
version: '0'
|
|
168
|
+
requirements: []
|
|
169
|
+
rubygems_version: 3.4.22
|
|
170
|
+
signing_key:
|
|
171
|
+
specification_version: 4
|
|
172
|
+
summary: Converts potentially-messy HTML to clean Markdown using opinionated, configurable
|
|
173
|
+
processing rules.
|
|
174
|
+
test_files: []
|