html-to-markdown 3.4.0 → 3.6.0.pre.rc.23

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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -0
  3. data/README.md +347 -0
  4. data/Steepfile +10 -2
  5. data/ext/html_to_markdown_rb/Cargo.toml +3 -2
  6. data/ext/html_to_markdown_rb/extconf.rb +5 -5
  7. data/ext/html_to_markdown_rb/native/Cargo.lock +962 -0
  8. data/ext/html_to_markdown_rb/native/Cargo.toml +6 -11
  9. data/ext/html_to_markdown_rb/native/extconf.rb +14 -0
  10. data/ext/html_to_markdown_rb/src/lib.rs +1715 -646
  11. data/lib/html_to_markdown/native.rb +913 -37
  12. data/lib/html_to_markdown/version.rb +3 -3
  13. data/lib/html_to_markdown.rb +9 -4
  14. data/lib/html_to_markdown_rb.so +0 -0
  15. data/sig/types.rbs +59 -292
  16. metadata +32 -179
  17. data/ext/html_to_markdown_rb/Makefile +0 -592
  18. data/lib/bin/html-to-markdown +0 -0
  19. data/vendor/Cargo.toml +0 -33
  20. data/vendor/html-to-markdown-rs/Cargo.toml +0 -54
  21. data/vendor/html-to-markdown-rs/README.md +0 -278
  22. data/vendor/html-to-markdown-rs/examples/basic.rs +0 -24
  23. data/vendor/html-to-markdown-rs/examples/table.rs +0 -25
  24. data/vendor/html-to-markdown-rs/examples/test_deser.rs +0 -12
  25. data/vendor/html-to-markdown-rs/examples/test_escape.rs +0 -58
  26. data/vendor/html-to-markdown-rs/examples/test_inline_formatting.rs +0 -113
  27. data/vendor/html-to-markdown-rs/examples/test_lists.rs +0 -39
  28. data/vendor/html-to-markdown-rs/examples/test_semantic_tags.rs +0 -89
  29. data/vendor/html-to-markdown-rs/examples/test_tables.rs +0 -100
  30. data/vendor/html-to-markdown-rs/examples/test_task_lists.rs +0 -61
  31. data/vendor/html-to-markdown-rs/examples/test_whitespace.rs +0 -34
  32. data/vendor/html-to-markdown-rs/src/convert_api.rs +0 -349
  33. data/vendor/html-to-markdown-rs/src/converter/block/blockquote.rs +0 -178
  34. data/vendor/html-to-markdown-rs/src/converter/block/container.rs +0 -114
  35. data/vendor/html-to-markdown-rs/src/converter/block/div.rs +0 -149
  36. data/vendor/html-to-markdown-rs/src/converter/block/heading.rs +0 -428
  37. data/vendor/html-to-markdown-rs/src/converter/block/horizontal_rule.rs +0 -103
  38. data/vendor/html-to-markdown-rs/src/converter/block/line_break.rs +0 -89
  39. data/vendor/html-to-markdown-rs/src/converter/block/mod.rs +0 -10
  40. data/vendor/html-to-markdown-rs/src/converter/block/paragraph.rs +0 -140
  41. data/vendor/html-to-markdown-rs/src/converter/block/preformatted.rs +0 -298
  42. data/vendor/html-to-markdown-rs/src/converter/block/table/builder.rs +0 -453
  43. data/vendor/html-to-markdown-rs/src/converter/block/table/caption.rs +0 -44
  44. data/vendor/html-to-markdown-rs/src/converter/block/table/cell.rs +0 -276
  45. data/vendor/html-to-markdown-rs/src/converter/block/table/cells.rs +0 -336
  46. data/vendor/html-to-markdown-rs/src/converter/block/table/layout.rs +0 -58
  47. data/vendor/html-to-markdown-rs/src/converter/block/table/mod.rs +0 -266
  48. data/vendor/html-to-markdown-rs/src/converter/block/table/scanner.rs +0 -146
  49. data/vendor/html-to-markdown-rs/src/converter/block/table/utils.rs +0 -34
  50. data/vendor/html-to-markdown-rs/src/converter/block/unknown.rs +0 -138
  51. data/vendor/html-to-markdown-rs/src/converter/context.rs +0 -208
  52. data/vendor/html-to-markdown-rs/src/converter/dom_context.rs +0 -337
  53. data/vendor/html-to-markdown-rs/src/converter/form/elements.rs +0 -770
  54. data/vendor/html-to-markdown-rs/src/converter/form/mod.rs +0 -82
  55. data/vendor/html-to-markdown-rs/src/converter/format/djot.rs +0 -64
  56. data/vendor/html-to-markdown-rs/src/converter/format/markdown.rs +0 -59
  57. data/vendor/html-to-markdown-rs/src/converter/format/mod.rs +0 -43
  58. data/vendor/html-to-markdown-rs/src/converter/handlers/blockquote.rs +0 -173
  59. data/vendor/html-to-markdown-rs/src/converter/handlers/code_block.rs +0 -434
  60. data/vendor/html-to-markdown-rs/src/converter/handlers/graphic.rs +0 -234
  61. data/vendor/html-to-markdown-rs/src/converter/handlers/image.rs +0 -282
  62. data/vendor/html-to-markdown-rs/src/converter/handlers/link.rs +0 -316
  63. data/vendor/html-to-markdown-rs/src/converter/handlers/mod.rs +0 -26
  64. data/vendor/html-to-markdown-rs/src/converter/inline/code.rs +0 -306
  65. data/vendor/html-to-markdown-rs/src/converter/inline/emphasis.rs +0 -345
  66. data/vendor/html-to-markdown-rs/src/converter/inline/link.rs +0 -428
  67. data/vendor/html-to-markdown-rs/src/converter/inline/mod.rs +0 -237
  68. data/vendor/html-to-markdown-rs/src/converter/inline/ruby.rs +0 -337
  69. data/vendor/html-to-markdown-rs/src/converter/inline/semantic/marks.rs +0 -566
  70. data/vendor/html-to-markdown-rs/src/converter/inline/semantic/mod.rs +0 -86
  71. data/vendor/html-to-markdown-rs/src/converter/inline/semantic/typography.rs +0 -558
  72. data/vendor/html-to-markdown-rs/src/converter/list/definition.rs +0 -232
  73. data/vendor/html-to-markdown-rs/src/converter/list/item.rs +0 -332
  74. data/vendor/html-to-markdown-rs/src/converter/list/mod.rs +0 -70
  75. data/vendor/html-to-markdown-rs/src/converter/list/ordered.rs +0 -201
  76. data/vendor/html-to-markdown-rs/src/converter/list/unordered.rs +0 -195
  77. data/vendor/html-to-markdown-rs/src/converter/list/utils.rs +0 -314
  78. data/vendor/html-to-markdown-rs/src/converter/main.rs +0 -710
  79. data/vendor/html-to-markdown-rs/src/converter/main_helpers.rs +0 -452
  80. data/vendor/html-to-markdown-rs/src/converter/media/embedded.rs +0 -393
  81. data/vendor/html-to-markdown-rs/src/converter/media/graphic.rs +0 -4
  82. data/vendor/html-to-markdown-rs/src/converter/media/image.rs +0 -183
  83. data/vendor/html-to-markdown-rs/src/converter/media/mod.rs +0 -87
  84. data/vendor/html-to-markdown-rs/src/converter/media/svg.rs +0 -280
  85. data/vendor/html-to-markdown-rs/src/converter/metadata.rs +0 -220
  86. data/vendor/html-to-markdown-rs/src/converter/mod.rs +0 -156
  87. data/vendor/html-to-markdown-rs/src/converter/plain_text.rs +0 -516
  88. data/vendor/html-to-markdown-rs/src/converter/preprocessing_helpers.rs +0 -201
  89. data/vendor/html-to-markdown-rs/src/converter/reference_collector.rs +0 -69
  90. data/vendor/html-to-markdown-rs/src/converter/semantic/attributes.rs +0 -269
  91. data/vendor/html-to-markdown-rs/src/converter/semantic/definition_list.rs +0 -266
  92. data/vendor/html-to-markdown-rs/src/converter/semantic/figure.rs +0 -391
  93. data/vendor/html-to-markdown-rs/src/converter/semantic/mod.rs +0 -112
  94. data/vendor/html-to-markdown-rs/src/converter/semantic/sectioning.rs +0 -85
  95. data/vendor/html-to-markdown-rs/src/converter/semantic/summary.rs +0 -324
  96. data/vendor/html-to-markdown-rs/src/converter/text/mod.rs +0 -8
  97. data/vendor/html-to-markdown-rs/src/converter/text/processing.rs +0 -56
  98. data/vendor/html-to-markdown-rs/src/converter/text_node.rs +0 -269
  99. data/vendor/html-to-markdown-rs/src/converter/utility/attributes.rs +0 -151
  100. data/vendor/html-to-markdown-rs/src/converter/utility/caching.rs +0 -74
  101. data/vendor/html-to-markdown-rs/src/converter/utility/content.rs +0 -271
  102. data/vendor/html-to-markdown-rs/src/converter/utility/mod.rs +0 -17
  103. data/vendor/html-to-markdown-rs/src/converter/utility/preprocessing.rs +0 -1002
  104. data/vendor/html-to-markdown-rs/src/converter/utility/serialization.rs +0 -126
  105. data/vendor/html-to-markdown-rs/src/converter/utility/siblings.rs +0 -97
  106. data/vendor/html-to-markdown-rs/src/converter/visitor_hooks.rs +0 -189
  107. data/vendor/html-to-markdown-rs/src/error.rs +0 -43
  108. data/vendor/html-to-markdown-rs/src/exports.rs +0 -24
  109. data/vendor/html-to-markdown-rs/src/inline_images.rs +0 -336
  110. data/vendor/html-to-markdown-rs/src/lib.rs +0 -139
  111. data/vendor/html-to-markdown-rs/src/metadata/collector.rs +0 -457
  112. data/vendor/html-to-markdown-rs/src/metadata/config.rs +0 -394
  113. data/vendor/html-to-markdown-rs/src/metadata/extraction.rs +0 -398
  114. data/vendor/html-to-markdown-rs/src/metadata/mod.rs +0 -288
  115. data/vendor/html-to-markdown-rs/src/metadata/types.rs +0 -477
  116. data/vendor/html-to-markdown-rs/src/options/conversion.rs +0 -559
  117. data/vendor/html-to-markdown-rs/src/options/inline_image.rs +0 -111
  118. data/vendor/html-to-markdown-rs/src/options/mod.rs +0 -20
  119. data/vendor/html-to-markdown-rs/src/options/preprocessing.rs +0 -201
  120. data/vendor/html-to-markdown-rs/src/options/validation.rs +0 -416
  121. data/vendor/html-to-markdown-rs/src/prelude.rs +0 -1
  122. data/vendor/html-to-markdown-rs/src/rcdom.rs +0 -487
  123. data/vendor/html-to-markdown-rs/src/text.rs +0 -358
  124. data/vendor/html-to-markdown-rs/src/types/document.rs +0 -191
  125. data/vendor/html-to-markdown-rs/src/types/mod.rs +0 -17
  126. data/vendor/html-to-markdown-rs/src/types/result.rs +0 -54
  127. data/vendor/html-to-markdown-rs/src/types/structure_builder.rs +0 -791
  128. data/vendor/html-to-markdown-rs/src/types/structure_collector.rs +0 -483
  129. data/vendor/html-to-markdown-rs/src/types/tables.rs +0 -52
  130. data/vendor/html-to-markdown-rs/src/types/warnings.rs +0 -33
  131. data/vendor/html-to-markdown-rs/src/validation.rs +0 -158
  132. data/vendor/html-to-markdown-rs/src/visitor/default_impl.rs +0 -63
  133. data/vendor/html-to-markdown-rs/src/visitor/mod.rs +0 -41
  134. data/vendor/html-to-markdown-rs/src/visitor/traits.rs +0 -370
  135. data/vendor/html-to-markdown-rs/src/visitor/types.rs +0 -319
  136. data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/callbacks/mod.rs +0 -1
  137. data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/content.rs +0 -126
  138. data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/mod.rs +0 -27
  139. data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/state.rs +0 -110
  140. data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/traversal.rs +0 -250
  141. data/vendor/html-to-markdown-rs/src/visitor_helpers.rs +0 -597
  142. data/vendor/html-to-markdown-rs/src/wrapper/sync.rs +0 -413
  143. data/vendor/html-to-markdown-rs/src/wrapper/utils.rs +0 -290
  144. data/vendor/html-to-markdown-rs/src/wrapper.rs +0 -9
  145. data/vendor/html-to-markdown-rs/tests/br_in_inline_test.rs +0 -87
  146. data/vendor/html-to-markdown-rs/tests/commonmark_compliance_test.rs +0 -297
  147. data/vendor/html-to-markdown-rs/tests/djot_output_test.rs +0 -153
  148. data/vendor/html-to-markdown-rs/tests/exclude_selectors_test.rs +0 -132
  149. data/vendor/html-to-markdown-rs/tests/integration_test.rs +0 -631
  150. data/vendor/html-to-markdown-rs/tests/issue_121_regressions.rs +0 -49
  151. data/vendor/html-to-markdown-rs/tests/issue_127_regressions.rs +0 -58
  152. data/vendor/html-to-markdown-rs/tests/issue_128_regressions.rs +0 -17
  153. data/vendor/html-to-markdown-rs/tests/issue_131_regressions.rs +0 -41
  154. data/vendor/html-to-markdown-rs/tests/issue_134_regressions.rs +0 -40
  155. data/vendor/html-to-markdown-rs/tests/issue_139_regressions.rs +0 -26
  156. data/vendor/html-to-markdown-rs/tests/issue_140_regressions.rs +0 -185
  157. data/vendor/html-to-markdown-rs/tests/issue_143_regressions.rs +0 -100
  158. data/vendor/html-to-markdown-rs/tests/issue_145_regressions.rs +0 -133
  159. data/vendor/html-to-markdown-rs/tests/issue_146_regressions.rs +0 -144
  160. data/vendor/html-to-markdown-rs/tests/issue_176_regressions.rs +0 -62
  161. data/vendor/html-to-markdown-rs/tests/issue_190_regressions.rs +0 -128
  162. data/vendor/html-to-markdown-rs/tests/issue_199_regressions.rs +0 -20
  163. data/vendor/html-to-markdown-rs/tests/issue_200_regressions.rs +0 -62
  164. data/vendor/html-to-markdown-rs/tests/issue_212_regressions.rs +0 -68
  165. data/vendor/html-to-markdown-rs/tests/issue_216_217_regressions.rs +0 -87
  166. data/vendor/html-to-markdown-rs/tests/issue_336_regressions.rs +0 -74
  167. data/vendor/html-to-markdown-rs/tests/issue_339_regressions.rs +0 -92
  168. data/vendor/html-to-markdown-rs/tests/issue_347_regressions.rs +0 -154
  169. data/vendor/html-to-markdown-rs/tests/issue_348_visitor_plain.rs +0 -93
  170. data/vendor/html-to-markdown-rs/tests/json_ld_script_extraction.rs +0 -44
  171. data/vendor/html-to-markdown-rs/tests/lists_test.rs +0 -199
  172. data/vendor/html-to-markdown-rs/tests/plain_output_test.rs +0 -273
  173. data/vendor/html-to-markdown-rs/tests/preprocessing_tests.rs +0 -61
  174. data/vendor/html-to-markdown-rs/tests/reference_links_test.rs +0 -169
  175. data/vendor/html-to-markdown-rs/tests/sectioning_elements_test.rs +0 -137
  176. data/vendor/html-to-markdown-rs/tests/skip_images_test.rs +0 -522
  177. data/vendor/html-to-markdown-rs/tests/tables_test.rs +0 -743
  178. data/vendor/html-to-markdown-rs/tests/test_custom_elements.rs +0 -41
  179. data/vendor/html-to-markdown-rs/tests/test_issue_187.rs +0 -204
  180. data/vendor/html-to-markdown-rs/tests/test_issue_218.rs +0 -68
  181. data/vendor/html-to-markdown-rs/tests/test_issue_277.rs +0 -77
  182. data/vendor/html-to-markdown-rs/tests/test_max_depth.rs +0 -82
  183. data/vendor/html-to-markdown-rs/tests/test_nested_simple.rs +0 -45
  184. data/vendor/html-to-markdown-rs/tests/test_script_style_stripping.rs +0 -396
  185. data/vendor/html-to-markdown-rs/tests/test_spa_bisect.rs +0 -34
  186. data/vendor/html-to-markdown-rs/tests/visitor_code_integration_test.rs +0 -121
  187. data/vendor/html-to-markdown-rs/tests/visitor_integration_test.rs +0 -1190
  188. data/vendor/html-to-markdown-rs/tests/xml_tables_test.rs +0 -372
@@ -1,559 +0,0 @@
1
- #![allow(clippy::cast_precision_loss, clippy::cast_sign_loss, clippy::unused_self)]
2
-
3
- //! Main conversion options with builder pattern.
4
-
5
- use crate::options::preprocessing::PreprocessingOptions;
6
- use crate::options::validation::{
7
- CodeBlockStyle, HeadingStyle, HighlightStyle, LinkStyle, ListIndentType, NewlineStyle, OutputFormat, WhitespaceMode,
8
- };
9
-
10
- /// Main conversion options for HTML to Markdown conversion.
11
- ///
12
- /// Use [`ConversionOptions::builder()`] to construct, or [`Default::default()`] for defaults.
13
- ///
14
- /// # Example
15
- ///
16
- /// ```text
17
- /// use html_to_markdown_rs::ConversionOptions;
18
- ///
19
- /// let options = ConversionOptions::builder()
20
- /// .heading_style(HeadingStyle::Atx)
21
- /// .wrap(true)
22
- /// .wrap_width(100)
23
- /// .build();
24
- /// ```
25
- #[derive(Debug, Clone)]
26
- #[cfg_attr(
27
- any(feature = "serde", feature = "metadata"),
28
- derive(serde::Serialize, serde::Deserialize)
29
- )]
30
- #[cfg_attr(any(feature = "serde", feature = "metadata"), serde(default, deny_unknown_fields))]
31
- pub struct ConversionOptions {
32
- /// Heading style to use in Markdown output (ATX `#` or Setext underline).
33
- pub heading_style: HeadingStyle,
34
- /// How to indent nested list items (spaces or tab).
35
- pub list_indent_type: ListIndentType,
36
- /// Number of spaces (or tabs) to use for each level of list indentation.
37
- pub list_indent_width: usize,
38
- /// Bullet character(s) to use for unordered list items (e.g. `"-"`, `"*"`).
39
- pub bullets: String,
40
- /// Character used for bold/italic emphasis markers (`*` or `_`).
41
- pub strong_em_symbol: char,
42
- /// Escape `*` characters in plain text to avoid unintended bold/italic.
43
- pub escape_asterisks: bool,
44
- /// Escape `_` characters in plain text to avoid unintended bold/italic.
45
- pub escape_underscores: bool,
46
- /// Escape miscellaneous Markdown metacharacters (`[]()#` etc.) in plain text.
47
- pub escape_misc: bool,
48
- /// Escape ASCII characters that have special meaning in certain Markdown dialects.
49
- pub escape_ascii: bool,
50
- /// Default language annotation for fenced code blocks that have no language hint.
51
- pub code_language: String,
52
- /// Automatically convert bare URLs into Markdown autolinks.
53
- pub autolinks: bool,
54
- /// Emit a default title when no `<title>` tag is present.
55
- pub default_title: bool,
56
- /// Render `<br>` elements inside table cells as literal line breaks.
57
- pub br_in_tables: bool,
58
- /// Style used for `<mark>` / highlighted text (e.g. `==text==`).
59
- pub highlight_style: HighlightStyle,
60
- /// Extract `<meta>` and `<head>` information into the result metadata.
61
- pub extract_metadata: bool,
62
- /// Controls how whitespace is normalised during conversion.
63
- pub whitespace_mode: WhitespaceMode,
64
- /// Strip all newlines from the output, producing a single-line result.
65
- pub strip_newlines: bool,
66
- /// Wrap long lines at [`wrap_width`](Self::wrap_width) characters.
67
- pub wrap: bool,
68
- /// Maximum line width when [`wrap`](Self::wrap) is enabled (default `80`).
69
- pub wrap_width: usize,
70
- /// Treat the entire document as inline content (no block-level wrappers).
71
- pub convert_as_inline: bool,
72
- /// Markdown notation for subscript text (e.g. `"~"`).
73
- pub sub_symbol: String,
74
- /// Markdown notation for superscript text (e.g. `"^"`).
75
- pub sup_symbol: String,
76
- /// How to encode hard line breaks (`<br>`) in Markdown.
77
- pub newline_style: NewlineStyle,
78
- /// Style used for fenced code blocks (backticks or tilde).
79
- pub code_block_style: CodeBlockStyle,
80
- /// HTML tag names whose `<img>` children are kept inline instead of block.
81
- pub keep_inline_images_in: Vec<String>,
82
- /// Pre-processing options applied to the HTML before conversion.
83
- pub preprocessing: PreprocessingOptions,
84
- /// Expected character encoding of the input HTML (default `"utf-8"`).
85
- pub encoding: String,
86
- /// Emit debug information during conversion.
87
- pub debug: bool,
88
- /// HTML tag names whose content is stripped from the output entirely.
89
- pub strip_tags: Vec<String>,
90
- /// HTML tag names that are preserved verbatim in the output.
91
- pub preserve_tags: Vec<String>,
92
- /// Skip conversion of `<img>` elements (omit images from output).
93
- pub skip_images: bool,
94
- /// Link rendering style (inline or reference).
95
- pub link_style: LinkStyle,
96
- /// Target output format (Markdown, plain text, etc.).
97
- pub output_format: OutputFormat,
98
- /// Include structured document tree in result.
99
- pub include_document_structure: bool,
100
- /// Extract inline images from data URIs and SVGs.
101
- pub extract_images: bool,
102
- /// Maximum decoded image size in bytes (default 5MB).
103
- pub max_image_size: u64,
104
- /// Capture SVG elements as images.
105
- pub capture_svg: bool,
106
- /// Infer image dimensions from data.
107
- pub infer_dimensions: bool,
108
- /// Maximum DOM traversal depth. `None` means unlimited.
109
- /// When set, subtrees beyond this depth are silently truncated.
110
- pub max_depth: Option<usize>,
111
- /// CSS selectors for elements to exclude entirely (element + all content).
112
- ///
113
- /// Unlike `strip_tags` (which removes the tag wrapper but keeps children),
114
- /// excluded elements and all their descendants are dropped from the output.
115
- /// Supports any CSS selector that `tl` supports: tag names, `.class`,
116
- /// `#id`, `[attribute]`, etc.
117
- ///
118
- /// Invalid selectors are silently skipped at conversion time.
119
- ///
120
- /// Example: `vec![".cookie-banner".into(), "#ad-container".into(), "[role='complementary']".into()]`
121
- #[cfg_attr(any(feature = "serde", feature = "metadata"), serde(default))]
122
- pub exclude_selectors: Vec<String>,
123
-
124
- /// Optional visitor for custom traversal logic.
125
- ///
126
- /// When set, the visitor's callbacks are invoked for matching HTML elements
127
- /// during conversion, allowing custom output, skipping, or HTML preservation.
128
- /// See [`crate::visitor::HtmlVisitor`].
129
- #[cfg(feature = "visitor")]
130
- #[cfg_attr(any(feature = "serde", feature = "metadata"), serde(skip))]
131
- pub visitor: Option<crate::visitor::VisitorHandle>,
132
- }
133
-
134
- impl Default for ConversionOptions {
135
- fn default() -> Self {
136
- Self {
137
- heading_style: HeadingStyle::default(),
138
- list_indent_type: ListIndentType::default(),
139
- list_indent_width: 2,
140
- bullets: "-*+".to_string(),
141
- strong_em_symbol: '*',
142
- escape_asterisks: false,
143
- escape_underscores: false,
144
- escape_misc: false,
145
- escape_ascii: false,
146
- code_language: String::new(),
147
- autolinks: true,
148
- default_title: false,
149
- br_in_tables: false,
150
- highlight_style: HighlightStyle::default(),
151
- extract_metadata: true,
152
- whitespace_mode: WhitespaceMode::default(),
153
- strip_newlines: false,
154
- wrap: false,
155
- wrap_width: 80,
156
- convert_as_inline: false,
157
- sub_symbol: String::new(),
158
- sup_symbol: String::new(),
159
- newline_style: NewlineStyle::Spaces,
160
- code_block_style: CodeBlockStyle::default(),
161
- keep_inline_images_in: Vec::new(),
162
- preprocessing: PreprocessingOptions::default(),
163
- encoding: "utf-8".to_string(),
164
- debug: false,
165
- strip_tags: Vec::new(),
166
- preserve_tags: Vec::new(),
167
- skip_images: false,
168
- link_style: LinkStyle::default(),
169
- output_format: OutputFormat::default(),
170
- include_document_structure: false,
171
- extract_images: false,
172
- max_image_size: 5_242_880,
173
- capture_svg: false,
174
- infer_dimensions: true,
175
- max_depth: None,
176
- exclude_selectors: Vec::new(),
177
- #[cfg(feature = "visitor")]
178
- visitor: None,
179
- }
180
- }
181
- }
182
-
183
- impl ConversionOptions {
184
- /// Create a new builder with default values.
185
- #[must_use]
186
- pub fn builder() -> ConversionOptionsBuilder {
187
- ConversionOptionsBuilder(Self::default())
188
- }
189
- }
190
-
191
- // ── Builder ─────────────────────────────────────────────────────────────────
192
-
193
- /// Builder for [`ConversionOptions`].
194
- ///
195
- /// All fields start with default values. Call `.build()` to produce the final options.
196
- #[derive(Debug, Clone)]
197
- pub struct ConversionOptionsBuilder(ConversionOptions);
198
-
199
- macro_rules! builder_setter {
200
- ($name:ident, $ty:ty) => {
201
- /// Set the value.
202
- #[must_use]
203
- pub fn $name(mut self, value: $ty) -> Self {
204
- self.0.$name = value;
205
- self
206
- }
207
- };
208
- }
209
-
210
- macro_rules! builder_setter_into {
211
- ($name:ident, $ty:ty) => {
212
- /// Set the value.
213
- #[must_use]
214
- pub fn $name(mut self, value: impl Into<$ty>) -> Self {
215
- self.0.$name = value.into();
216
- self
217
- }
218
- };
219
- }
220
-
221
- impl ConversionOptionsBuilder {
222
- // Output control
223
- builder_setter!(output_format, OutputFormat);
224
- builder_setter!(include_document_structure, bool);
225
- builder_setter!(extract_metadata, bool);
226
- builder_setter!(extract_images, bool);
227
-
228
- // Markdown formatting
229
- builder_setter!(heading_style, HeadingStyle);
230
- builder_setter!(list_indent_type, ListIndentType);
231
- builder_setter!(list_indent_width, usize);
232
- builder_setter_into!(bullets, String);
233
- builder_setter!(strong_em_symbol, char);
234
- builder_setter!(code_block_style, CodeBlockStyle);
235
- builder_setter!(newline_style, NewlineStyle);
236
- builder_setter!(highlight_style, HighlightStyle);
237
- builder_setter_into!(code_language, String);
238
- builder_setter!(link_style, LinkStyle);
239
- builder_setter!(autolinks, bool);
240
- builder_setter!(default_title, bool);
241
- builder_setter!(br_in_tables, bool);
242
- builder_setter_into!(sub_symbol, String);
243
- builder_setter_into!(sup_symbol, String);
244
-
245
- // Escaping
246
- builder_setter!(escape_asterisks, bool);
247
- builder_setter!(escape_underscores, bool);
248
- builder_setter!(escape_misc, bool);
249
- builder_setter!(escape_ascii, bool);
250
-
251
- // Whitespace / wrapping
252
- builder_setter!(whitespace_mode, WhitespaceMode);
253
- builder_setter!(strip_newlines, bool);
254
- builder_setter!(wrap, bool);
255
- builder_setter!(wrap_width, usize);
256
-
257
- // Element handling
258
- builder_setter!(convert_as_inline, bool);
259
- builder_setter!(skip_images, bool);
260
-
261
- /// Set the list of HTML tag names whose content is stripped from output.
262
- #[must_use]
263
- pub fn strip_tags(mut self, tags: Vec<String>) -> Self {
264
- self.0.strip_tags = tags;
265
- self
266
- }
267
-
268
- /// Set the list of HTML tag names that are preserved verbatim in output.
269
- #[must_use]
270
- pub fn preserve_tags(mut self, tags: Vec<String>) -> Self {
271
- self.0.preserve_tags = tags;
272
- self
273
- }
274
-
275
- /// Set the list of HTML tag names whose `<img>` children are kept inline.
276
- #[must_use]
277
- pub fn keep_inline_images_in(mut self, tags: Vec<String>) -> Self {
278
- self.0.keep_inline_images_in = tags;
279
- self
280
- }
281
-
282
- // Image extraction config
283
- builder_setter!(max_image_size, u64);
284
- builder_setter!(capture_svg, bool);
285
- builder_setter!(infer_dimensions, bool);
286
- builder_setter!(max_depth, Option<usize>);
287
-
288
- /// Set the list of CSS selectors for elements to exclude entirely from output.
289
- #[must_use]
290
- pub fn exclude_selectors(mut self, selectors: Vec<String>) -> Self {
291
- self.0.exclude_selectors = selectors;
292
- self
293
- }
294
-
295
- /// Set the visitor used during conversion.
296
- #[cfg(feature = "visitor")]
297
- #[must_use]
298
- pub fn visitor(mut self, visitor: Option<crate::visitor::VisitorHandle>) -> Self {
299
- self.0.visitor = visitor;
300
- self
301
- }
302
-
303
- // Preprocessing
304
- /// Set the pre-processing options applied to the HTML before conversion.
305
- #[must_use]
306
- pub fn preprocessing(mut self, preprocessing: PreprocessingOptions) -> Self {
307
- self.0.preprocessing = preprocessing;
308
- self
309
- }
310
-
311
- // Encoding
312
- builder_setter_into!(encoding, String);
313
-
314
- // Debug
315
- builder_setter!(debug, bool);
316
-
317
- /// Build the final [`ConversionOptions`].
318
- #[must_use]
319
- pub fn build(self) -> ConversionOptions {
320
- self.0
321
- }
322
- }
323
-
324
- // ── ConversionOptionsUpdate (for binding crate compatibility) ────────────
325
-
326
- use crate::options::preprocessing::PreprocessingOptionsUpdate;
327
-
328
- /// Partial update for `ConversionOptions`.
329
- ///
330
- /// Uses `Option<T>` fields for selective updates. Bindings use this to construct
331
- /// options from language-native types. Prefer [`ConversionOptionsBuilder`] for Rust code.
332
- #[derive(Debug, Clone, Default)]
333
- #[cfg_attr(
334
- any(feature = "serde", feature = "metadata"),
335
- derive(serde::Serialize, serde::Deserialize)
336
- )]
337
- #[cfg_attr(any(feature = "serde", feature = "metadata"), serde(deny_unknown_fields))]
338
- pub struct ConversionOptionsUpdate {
339
- /// Optional override for [`ConversionOptions::heading_style`].
340
- pub heading_style: Option<HeadingStyle>,
341
- /// Optional override for [`ConversionOptions::list_indent_type`].
342
- pub list_indent_type: Option<ListIndentType>,
343
- /// Optional override for [`ConversionOptions::list_indent_width`].
344
- pub list_indent_width: Option<usize>,
345
- /// Optional override for [`ConversionOptions::bullets`].
346
- pub bullets: Option<String>,
347
- /// Optional override for [`ConversionOptions::strong_em_symbol`].
348
- pub strong_em_symbol: Option<char>,
349
- /// Optional override for [`ConversionOptions::escape_asterisks`].
350
- pub escape_asterisks: Option<bool>,
351
- /// Optional override for [`ConversionOptions::escape_underscores`].
352
- pub escape_underscores: Option<bool>,
353
- /// Optional override for [`ConversionOptions::escape_misc`].
354
- pub escape_misc: Option<bool>,
355
- /// Optional override for [`ConversionOptions::escape_ascii`].
356
- pub escape_ascii: Option<bool>,
357
- /// Optional override for [`ConversionOptions::code_language`].
358
- pub code_language: Option<String>,
359
- /// Optional override for [`ConversionOptions::autolinks`].
360
- pub autolinks: Option<bool>,
361
- /// Optional override for [`ConversionOptions::default_title`].
362
- pub default_title: Option<bool>,
363
- /// Optional override for [`ConversionOptions::br_in_tables`].
364
- pub br_in_tables: Option<bool>,
365
- /// Optional override for [`ConversionOptions::highlight_style`].
366
- pub highlight_style: Option<HighlightStyle>,
367
- /// Optional override for [`ConversionOptions::extract_metadata`].
368
- pub extract_metadata: Option<bool>,
369
- /// Optional override for [`ConversionOptions::whitespace_mode`].
370
- pub whitespace_mode: Option<WhitespaceMode>,
371
- /// Optional override for [`ConversionOptions::strip_newlines`].
372
- pub strip_newlines: Option<bool>,
373
- /// Optional override for [`ConversionOptions::wrap`].
374
- pub wrap: Option<bool>,
375
- /// Optional override for [`ConversionOptions::wrap_width`].
376
- pub wrap_width: Option<usize>,
377
- /// Optional override for [`ConversionOptions::convert_as_inline`].
378
- pub convert_as_inline: Option<bool>,
379
- /// Optional override for [`ConversionOptions::sub_symbol`].
380
- pub sub_symbol: Option<String>,
381
- /// Optional override for [`ConversionOptions::sup_symbol`].
382
- pub sup_symbol: Option<String>,
383
- /// Optional override for [`ConversionOptions::newline_style`].
384
- pub newline_style: Option<NewlineStyle>,
385
- /// Optional override for [`ConversionOptions::code_block_style`].
386
- pub code_block_style: Option<CodeBlockStyle>,
387
- /// Optional override for [`ConversionOptions::keep_inline_images_in`].
388
- pub keep_inline_images_in: Option<Vec<String>>,
389
- /// Optional override for [`ConversionOptions::preprocessing`].
390
- pub preprocessing: Option<PreprocessingOptionsUpdate>,
391
- /// Optional override for [`ConversionOptions::encoding`].
392
- pub encoding: Option<String>,
393
- /// Optional override for [`ConversionOptions::debug`].
394
- pub debug: Option<bool>,
395
- /// Optional override for [`ConversionOptions::strip_tags`].
396
- pub strip_tags: Option<Vec<String>>,
397
- /// Optional override for [`ConversionOptions::preserve_tags`].
398
- pub preserve_tags: Option<Vec<String>>,
399
- /// Optional override for [`ConversionOptions::skip_images`].
400
- pub skip_images: Option<bool>,
401
- /// Optional override for [`ConversionOptions::link_style`].
402
- pub link_style: Option<LinkStyle>,
403
- /// Optional override for [`ConversionOptions::output_format`].
404
- pub output_format: Option<OutputFormat>,
405
- /// Optional override for [`ConversionOptions::include_document_structure`].
406
- pub include_document_structure: Option<bool>,
407
- /// Optional override for [`ConversionOptions::extract_images`].
408
- pub extract_images: Option<bool>,
409
- /// Optional override for [`ConversionOptions::max_image_size`].
410
- pub max_image_size: Option<u64>,
411
- /// Optional override for [`ConversionOptions::capture_svg`].
412
- pub capture_svg: Option<bool>,
413
- /// Optional override for [`ConversionOptions::infer_dimensions`].
414
- pub infer_dimensions: Option<bool>,
415
- /// Optional override for [`ConversionOptions::max_depth`].
416
- pub max_depth: Option<Option<usize>>,
417
- /// Optional override for [`ConversionOptions::exclude_selectors`].
418
- pub exclude_selectors: Option<Vec<String>>,
419
- /// Optional override for [`ConversionOptions::visitor`].
420
- #[cfg(feature = "visitor")]
421
- #[cfg_attr(any(feature = "serde", feature = "metadata"), serde(skip))]
422
- pub visitor: Option<crate::visitor::VisitorHandle>,
423
- }
424
-
425
- impl ConversionOptions {
426
- /// Apply a partial update to these conversion options.
427
- pub fn apply_update(&mut self, update: ConversionOptionsUpdate) {
428
- macro_rules! apply {
429
- ($field:ident) => {
430
- if let Some(v) = update.$field {
431
- self.$field = v;
432
- }
433
- };
434
- }
435
- apply!(heading_style);
436
- apply!(list_indent_type);
437
- apply!(list_indent_width);
438
- apply!(bullets);
439
- apply!(strong_em_symbol);
440
- apply!(escape_asterisks);
441
- apply!(escape_underscores);
442
- apply!(escape_misc);
443
- apply!(escape_ascii);
444
- apply!(code_language);
445
- apply!(autolinks);
446
- apply!(default_title);
447
- apply!(br_in_tables);
448
- apply!(highlight_style);
449
- apply!(extract_metadata);
450
- apply!(whitespace_mode);
451
- apply!(strip_newlines);
452
- apply!(wrap);
453
- apply!(wrap_width);
454
- apply!(convert_as_inline);
455
- apply!(sub_symbol);
456
- apply!(sup_symbol);
457
- apply!(newline_style);
458
- apply!(code_block_style);
459
- apply!(keep_inline_images_in);
460
- apply!(encoding);
461
- apply!(debug);
462
- apply!(strip_tags);
463
- apply!(preserve_tags);
464
- apply!(skip_images);
465
- apply!(link_style);
466
- apply!(output_format);
467
- apply!(include_document_structure);
468
- apply!(extract_images);
469
- apply!(max_image_size);
470
- apply!(capture_svg);
471
- apply!(infer_dimensions);
472
- apply!(max_depth);
473
- apply!(exclude_selectors);
474
- #[cfg(feature = "visitor")]
475
- if let Some(visitor) = update.visitor {
476
- self.visitor = Some(visitor);
477
- }
478
- if let Some(preprocessing) = update.preprocessing {
479
- self.preprocessing.apply_update(preprocessing);
480
- }
481
- }
482
-
483
- /// Create from a partial update, applying to defaults.
484
- #[must_use]
485
- pub fn from_update(update: ConversionOptionsUpdate) -> Self {
486
- let mut options = Self::default();
487
- options.apply_update(update);
488
- options
489
- }
490
- }
491
-
492
- impl From<ConversionOptionsUpdate> for ConversionOptions {
493
- fn from(update: ConversionOptionsUpdate) -> Self {
494
- Self::from_update(update)
495
- }
496
- }
497
-
498
- // ── Tests ───────────────────────────────────────────────────────────────────
499
-
500
- #[cfg(all(test, any(feature = "serde", feature = "metadata")))]
501
- mod tests {
502
- use super::*;
503
-
504
- #[test]
505
- fn test_conversion_options_serde() {
506
- let options = ConversionOptions::builder()
507
- .heading_style(HeadingStyle::AtxClosed)
508
- .list_indent_width(4)
509
- .bullets("*")
510
- .escape_asterisks(true)
511
- .whitespace_mode(WhitespaceMode::Strict)
512
- .build();
513
-
514
- let json = serde_json::to_string(&options).expect("Failed to serialize");
515
- let deserialized: ConversionOptions = serde_json::from_str(&json).expect("Failed to deserialize");
516
-
517
- assert_eq!(deserialized.list_indent_width, 4);
518
- assert_eq!(deserialized.bullets, "*");
519
- assert!(deserialized.escape_asterisks);
520
- assert_eq!(deserialized.heading_style, HeadingStyle::AtxClosed);
521
- assert_eq!(deserialized.whitespace_mode, WhitespaceMode::Strict);
522
- }
523
-
524
- #[test]
525
- fn test_conversion_options_partial_deserialization() {
526
- let partial_json = r#"{
527
- "heading_style": "atxclosed",
528
- "list_indent_width": 4,
529
- "bullets": "*"
530
- }"#;
531
-
532
- let deserialized: ConversionOptions =
533
- serde_json::from_str(partial_json).expect("Failed to deserialize partial JSON");
534
-
535
- assert_eq!(deserialized.heading_style, HeadingStyle::AtxClosed);
536
- assert_eq!(deserialized.list_indent_width, 4);
537
- assert_eq!(deserialized.bullets, "*");
538
- assert!(!deserialized.escape_asterisks);
539
- assert!(!deserialized.escape_underscores);
540
- assert_eq!(deserialized.list_indent_type, ListIndentType::Spaces);
541
- }
542
-
543
- #[test]
544
- fn test_builder_pattern() {
545
- let options = ConversionOptions::builder()
546
- .heading_style(HeadingStyle::Underlined)
547
- .wrap(true)
548
- .wrap_width(100)
549
- .include_document_structure(true)
550
- .extract_images(true)
551
- .build();
552
-
553
- assert_eq!(options.heading_style, HeadingStyle::Underlined);
554
- assert!(options.wrap);
555
- assert_eq!(options.wrap_width, 100);
556
- assert!(options.include_document_structure);
557
- assert!(options.extract_images);
558
- }
559
- }
@@ -1,111 +0,0 @@
1
- //! Inline image configuration.
2
- //!
3
- //! This module provides configuration for controlling how images are rendered
4
- //! within specific HTML elements.
5
-
6
- /// Inline image configuration that specifies contexts where images remain as markdown links.
7
- ///
8
- /// This is a wrapper type that provides semantic clarity for the vector of element
9
- /// names where inline images should be preserved.
10
- #[derive(Debug, Clone)]
11
- pub struct InlineImageConfig {
12
- /// HTML elements where images should remain as markdown links (not converted to alt text)
13
- pub keep_inline_images_in: Vec<String>,
14
- }
15
-
16
- impl InlineImageConfig {
17
- /// Create a new inline image configuration with an empty list.
18
- #[must_use]
19
- pub fn new() -> Self {
20
- Self {
21
- keep_inline_images_in: Vec::new(),
22
- }
23
- }
24
-
25
- /// Create a new inline image configuration from a list of element names.
26
- ///
27
- /// # Arguments
28
- ///
29
- /// * `elements` - A vector of HTML element names where inline images should be kept
30
- #[must_use]
31
- pub fn from_elements(elements: Vec<String>) -> Self {
32
- Self {
33
- keep_inline_images_in: elements,
34
- }
35
- }
36
-
37
- /// Add an element name to the list of elements where images are kept inline.
38
- ///
39
- /// # Arguments
40
- ///
41
- /// * `element` - The HTML element name to add (e.g., "p", "div")
42
- pub fn add_element(&mut self, element: String) {
43
- self.keep_inline_images_in.push(element);
44
- }
45
-
46
- /// Check if a given element should keep images inline.
47
- ///
48
- /// # Arguments
49
- ///
50
- /// * `element` - The HTML element name to check
51
- ///
52
- /// # Returns
53
- ///
54
- /// `true` if the element is in the configured list, `false` otherwise
55
- #[must_use]
56
- pub fn should_keep_images(&self, element: &str) -> bool {
57
- self.keep_inline_images_in.iter().any(|e| e == element)
58
- }
59
- }
60
-
61
- impl Default for InlineImageConfig {
62
- fn default() -> Self {
63
- Self::new()
64
- }
65
- }
66
-
67
- #[cfg(test)]
68
- mod tests {
69
- use super::*;
70
-
71
- #[test]
72
- fn test_inline_image_config_new() {
73
- let config = InlineImageConfig::new();
74
- assert_eq!(config.keep_inline_images_in.len(), 0);
75
- }
76
-
77
- #[test]
78
- fn test_inline_image_config_from_elements() {
79
- let elements = vec!["p".to_string(), "div".to_string()];
80
- let config = InlineImageConfig::from_elements(elements);
81
- assert_eq!(config.keep_inline_images_in.len(), 2);
82
- assert!(config.should_keep_images("p"));
83
- assert!(config.should_keep_images("div"));
84
- assert!(!config.should_keep_images("span"));
85
- }
86
-
87
- #[test]
88
- fn test_inline_image_config_add_element() {
89
- let mut config = InlineImageConfig::new();
90
- config.add_element("p".to_string());
91
- config.add_element("div".to_string());
92
-
93
- assert_eq!(config.keep_inline_images_in.len(), 2);
94
- assert!(config.should_keep_images("p"));
95
- assert!(config.should_keep_images("div"));
96
- }
97
-
98
- #[test]
99
- fn test_inline_image_config_should_keep_images() {
100
- let config = InlineImageConfig::from_elements(vec!["figure".to_string()]);
101
- assert!(config.should_keep_images("figure"));
102
- assert!(!config.should_keep_images("p"));
103
- }
104
-
105
- #[test]
106
- fn test_inline_image_config_default() {
107
- let config = InlineImageConfig::default();
108
- assert_eq!(config.keep_inline_images_in.len(), 0);
109
- assert!(!config.should_keep_images("p"));
110
- }
111
- }
@@ -1,20 +0,0 @@
1
- //! Configuration options for HTML to Markdown conversion.
2
- //!
3
- //! This module provides comprehensive configuration options for customizing
4
- //! HTML to Markdown conversion behavior, including output formatting, preprocessing,
5
- //! and metadata extraction options.
6
-
7
- pub mod conversion;
8
- pub mod inline_image;
9
- pub mod preprocessing;
10
- pub mod validation;
11
-
12
- // Re-exports for easy access
13
- pub use conversion::{ConversionOptions, ConversionOptionsBuilder, ConversionOptionsUpdate};
14
- pub use preprocessing::{PreprocessingOptions, PreprocessingOptionsUpdate, PreprocessingPreset};
15
- pub use validation::{
16
- CodeBlockStyle, HeadingStyle, HighlightStyle, LinkStyle, ListIndentType, NewlineStyle, OutputFormat, WhitespaceMode,
17
- };
18
-
19
- // Note: InlineImageConfig is re-exported from the inline_images module,
20
- // not from this options module, to maintain compatibility with existing imports.