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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/changelog.md +7 -0
  3. data/lib/slamdown/conversion/configuration.rb +35 -0
  4. data/lib/slamdown/conversion/configuration_validator.rb +235 -0
  5. data/lib/slamdown/conversion/converter.rb +98 -0
  6. data/lib/slamdown/conversion/normalisation.rb +21 -0
  7. data/lib/slamdown/conversion/normalised_node.rb +40 -0
  8. data/lib/slamdown/conversion/normaliser/breaks.rb +104 -0
  9. data/lib/slamdown/conversion/normaliser/content.rb +174 -0
  10. data/lib/slamdown/conversion/normaliser/correction_diagnostics.rb +29 -0
  11. data/lib/slamdown/conversion/normaliser/element_actions.rb +423 -0
  12. data/lib/slamdown/conversion/normaliser/heading_levels.rb +45 -0
  13. data/lib/slamdown/conversion/normaliser/inline_semantics.rb +218 -0
  14. data/lib/slamdown/conversion/normaliser/node_factory.rb +112 -0
  15. data/lib/slamdown/conversion/normaliser/url_rewriter.rb +124 -0
  16. data/lib/slamdown/conversion/normaliser.rb +58 -0
  17. data/lib/slamdown/conversion/policy.rb +178 -0
  18. data/lib/slamdown/conversion/prepared_node.rb +23 -0
  19. data/lib/slamdown/conversion/preparer.rb +122 -0
  20. data/lib/slamdown/conversion/renderer.rb +432 -0
  21. data/lib/slamdown/conversion/rendering/entity_encoder.rb +56 -0
  22. data/lib/slamdown/conversion/rendering/escaper.rb +58 -0
  23. data/lib/slamdown/conversion/rendering/html.rb +183 -0
  24. data/lib/slamdown/conversion/rendering/result.rb +23 -0
  25. data/lib/slamdown/conversion/rendering/strategy.rb +157 -0
  26. data/lib/slamdown/conversion/semantic_extractor.rb +97 -0
  27. data/lib/slamdown/conversion/tables.rb +676 -0
  28. data/lib/slamdown/conversion.rb +34 -0
  29. data/lib/slamdown/diagnostic.rb +34 -0
  30. data/lib/slamdown/document.rb +107 -0
  31. data/lib/slamdown/errors.rb +25 -0
  32. data/lib/slamdown/immutable.rb +23 -0
  33. data/lib/slamdown/output.rb +30 -0
  34. data/lib/slamdown/parsing/html.rb +227 -0
  35. data/lib/slamdown/parsing/node.rb +50 -0
  36. data/lib/slamdown/parsing/parsed_node_adapter.rb +144 -0
  37. data/lib/slamdown/parsing.rb +17 -0
  38. data/lib/slamdown/version.rb +3 -0
  39. data/lib/slamdown.rb +10 -0
  40. data/readme.md +121 -0
  41. 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: []