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.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +347 -0
- data/Steepfile +10 -2
- data/ext/html_to_markdown_rb/Cargo.toml +3 -2
- data/ext/html_to_markdown_rb/extconf.rb +5 -5
- data/ext/html_to_markdown_rb/native/Cargo.lock +962 -0
- data/ext/html_to_markdown_rb/native/Cargo.toml +6 -11
- data/ext/html_to_markdown_rb/native/extconf.rb +14 -0
- data/ext/html_to_markdown_rb/src/lib.rs +1715 -646
- data/lib/html_to_markdown/native.rb +913 -37
- data/lib/html_to_markdown/version.rb +3 -3
- data/lib/html_to_markdown.rb +9 -4
- data/lib/html_to_markdown_rb.so +0 -0
- data/sig/types.rbs +59 -292
- metadata +32 -179
- data/ext/html_to_markdown_rb/Makefile +0 -592
- data/lib/bin/html-to-markdown +0 -0
- data/vendor/Cargo.toml +0 -33
- data/vendor/html-to-markdown-rs/Cargo.toml +0 -54
- data/vendor/html-to-markdown-rs/README.md +0 -278
- data/vendor/html-to-markdown-rs/examples/basic.rs +0 -24
- data/vendor/html-to-markdown-rs/examples/table.rs +0 -25
- data/vendor/html-to-markdown-rs/examples/test_deser.rs +0 -12
- data/vendor/html-to-markdown-rs/examples/test_escape.rs +0 -58
- data/vendor/html-to-markdown-rs/examples/test_inline_formatting.rs +0 -113
- data/vendor/html-to-markdown-rs/examples/test_lists.rs +0 -39
- data/vendor/html-to-markdown-rs/examples/test_semantic_tags.rs +0 -89
- data/vendor/html-to-markdown-rs/examples/test_tables.rs +0 -100
- data/vendor/html-to-markdown-rs/examples/test_task_lists.rs +0 -61
- data/vendor/html-to-markdown-rs/examples/test_whitespace.rs +0 -34
- data/vendor/html-to-markdown-rs/src/convert_api.rs +0 -349
- data/vendor/html-to-markdown-rs/src/converter/block/blockquote.rs +0 -178
- data/vendor/html-to-markdown-rs/src/converter/block/container.rs +0 -114
- data/vendor/html-to-markdown-rs/src/converter/block/div.rs +0 -149
- data/vendor/html-to-markdown-rs/src/converter/block/heading.rs +0 -428
- data/vendor/html-to-markdown-rs/src/converter/block/horizontal_rule.rs +0 -103
- data/vendor/html-to-markdown-rs/src/converter/block/line_break.rs +0 -89
- data/vendor/html-to-markdown-rs/src/converter/block/mod.rs +0 -10
- data/vendor/html-to-markdown-rs/src/converter/block/paragraph.rs +0 -140
- data/vendor/html-to-markdown-rs/src/converter/block/preformatted.rs +0 -298
- data/vendor/html-to-markdown-rs/src/converter/block/table/builder.rs +0 -453
- data/vendor/html-to-markdown-rs/src/converter/block/table/caption.rs +0 -44
- data/vendor/html-to-markdown-rs/src/converter/block/table/cell.rs +0 -276
- data/vendor/html-to-markdown-rs/src/converter/block/table/cells.rs +0 -336
- data/vendor/html-to-markdown-rs/src/converter/block/table/layout.rs +0 -58
- data/vendor/html-to-markdown-rs/src/converter/block/table/mod.rs +0 -266
- data/vendor/html-to-markdown-rs/src/converter/block/table/scanner.rs +0 -146
- data/vendor/html-to-markdown-rs/src/converter/block/table/utils.rs +0 -34
- data/vendor/html-to-markdown-rs/src/converter/block/unknown.rs +0 -138
- data/vendor/html-to-markdown-rs/src/converter/context.rs +0 -208
- data/vendor/html-to-markdown-rs/src/converter/dom_context.rs +0 -337
- data/vendor/html-to-markdown-rs/src/converter/form/elements.rs +0 -770
- data/vendor/html-to-markdown-rs/src/converter/form/mod.rs +0 -82
- data/vendor/html-to-markdown-rs/src/converter/format/djot.rs +0 -64
- data/vendor/html-to-markdown-rs/src/converter/format/markdown.rs +0 -59
- data/vendor/html-to-markdown-rs/src/converter/format/mod.rs +0 -43
- data/vendor/html-to-markdown-rs/src/converter/handlers/blockquote.rs +0 -173
- data/vendor/html-to-markdown-rs/src/converter/handlers/code_block.rs +0 -434
- data/vendor/html-to-markdown-rs/src/converter/handlers/graphic.rs +0 -234
- data/vendor/html-to-markdown-rs/src/converter/handlers/image.rs +0 -282
- data/vendor/html-to-markdown-rs/src/converter/handlers/link.rs +0 -316
- data/vendor/html-to-markdown-rs/src/converter/handlers/mod.rs +0 -26
- data/vendor/html-to-markdown-rs/src/converter/inline/code.rs +0 -306
- data/vendor/html-to-markdown-rs/src/converter/inline/emphasis.rs +0 -345
- data/vendor/html-to-markdown-rs/src/converter/inline/link.rs +0 -428
- data/vendor/html-to-markdown-rs/src/converter/inline/mod.rs +0 -237
- data/vendor/html-to-markdown-rs/src/converter/inline/ruby.rs +0 -337
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/marks.rs +0 -566
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/mod.rs +0 -86
- data/vendor/html-to-markdown-rs/src/converter/inline/semantic/typography.rs +0 -558
- data/vendor/html-to-markdown-rs/src/converter/list/definition.rs +0 -232
- data/vendor/html-to-markdown-rs/src/converter/list/item.rs +0 -332
- data/vendor/html-to-markdown-rs/src/converter/list/mod.rs +0 -70
- data/vendor/html-to-markdown-rs/src/converter/list/ordered.rs +0 -201
- data/vendor/html-to-markdown-rs/src/converter/list/unordered.rs +0 -195
- data/vendor/html-to-markdown-rs/src/converter/list/utils.rs +0 -314
- data/vendor/html-to-markdown-rs/src/converter/main.rs +0 -710
- data/vendor/html-to-markdown-rs/src/converter/main_helpers.rs +0 -452
- data/vendor/html-to-markdown-rs/src/converter/media/embedded.rs +0 -393
- data/vendor/html-to-markdown-rs/src/converter/media/graphic.rs +0 -4
- data/vendor/html-to-markdown-rs/src/converter/media/image.rs +0 -183
- data/vendor/html-to-markdown-rs/src/converter/media/mod.rs +0 -87
- data/vendor/html-to-markdown-rs/src/converter/media/svg.rs +0 -280
- data/vendor/html-to-markdown-rs/src/converter/metadata.rs +0 -220
- data/vendor/html-to-markdown-rs/src/converter/mod.rs +0 -156
- data/vendor/html-to-markdown-rs/src/converter/plain_text.rs +0 -516
- data/vendor/html-to-markdown-rs/src/converter/preprocessing_helpers.rs +0 -201
- data/vendor/html-to-markdown-rs/src/converter/reference_collector.rs +0 -69
- data/vendor/html-to-markdown-rs/src/converter/semantic/attributes.rs +0 -269
- data/vendor/html-to-markdown-rs/src/converter/semantic/definition_list.rs +0 -266
- data/vendor/html-to-markdown-rs/src/converter/semantic/figure.rs +0 -391
- data/vendor/html-to-markdown-rs/src/converter/semantic/mod.rs +0 -112
- data/vendor/html-to-markdown-rs/src/converter/semantic/sectioning.rs +0 -85
- data/vendor/html-to-markdown-rs/src/converter/semantic/summary.rs +0 -324
- data/vendor/html-to-markdown-rs/src/converter/text/mod.rs +0 -8
- data/vendor/html-to-markdown-rs/src/converter/text/processing.rs +0 -56
- data/vendor/html-to-markdown-rs/src/converter/text_node.rs +0 -269
- data/vendor/html-to-markdown-rs/src/converter/utility/attributes.rs +0 -151
- data/vendor/html-to-markdown-rs/src/converter/utility/caching.rs +0 -74
- data/vendor/html-to-markdown-rs/src/converter/utility/content.rs +0 -271
- data/vendor/html-to-markdown-rs/src/converter/utility/mod.rs +0 -17
- data/vendor/html-to-markdown-rs/src/converter/utility/preprocessing.rs +0 -1002
- data/vendor/html-to-markdown-rs/src/converter/utility/serialization.rs +0 -126
- data/vendor/html-to-markdown-rs/src/converter/utility/siblings.rs +0 -97
- data/vendor/html-to-markdown-rs/src/converter/visitor_hooks.rs +0 -189
- data/vendor/html-to-markdown-rs/src/error.rs +0 -43
- data/vendor/html-to-markdown-rs/src/exports.rs +0 -24
- data/vendor/html-to-markdown-rs/src/inline_images.rs +0 -336
- data/vendor/html-to-markdown-rs/src/lib.rs +0 -139
- data/vendor/html-to-markdown-rs/src/metadata/collector.rs +0 -457
- data/vendor/html-to-markdown-rs/src/metadata/config.rs +0 -394
- data/vendor/html-to-markdown-rs/src/metadata/extraction.rs +0 -398
- data/vendor/html-to-markdown-rs/src/metadata/mod.rs +0 -288
- data/vendor/html-to-markdown-rs/src/metadata/types.rs +0 -477
- data/vendor/html-to-markdown-rs/src/options/conversion.rs +0 -559
- data/vendor/html-to-markdown-rs/src/options/inline_image.rs +0 -111
- data/vendor/html-to-markdown-rs/src/options/mod.rs +0 -20
- data/vendor/html-to-markdown-rs/src/options/preprocessing.rs +0 -201
- data/vendor/html-to-markdown-rs/src/options/validation.rs +0 -416
- data/vendor/html-to-markdown-rs/src/prelude.rs +0 -1
- data/vendor/html-to-markdown-rs/src/rcdom.rs +0 -487
- data/vendor/html-to-markdown-rs/src/text.rs +0 -358
- data/vendor/html-to-markdown-rs/src/types/document.rs +0 -191
- data/vendor/html-to-markdown-rs/src/types/mod.rs +0 -17
- data/vendor/html-to-markdown-rs/src/types/result.rs +0 -54
- data/vendor/html-to-markdown-rs/src/types/structure_builder.rs +0 -791
- data/vendor/html-to-markdown-rs/src/types/structure_collector.rs +0 -483
- data/vendor/html-to-markdown-rs/src/types/tables.rs +0 -52
- data/vendor/html-to-markdown-rs/src/types/warnings.rs +0 -33
- data/vendor/html-to-markdown-rs/src/validation.rs +0 -158
- data/vendor/html-to-markdown-rs/src/visitor/default_impl.rs +0 -63
- data/vendor/html-to-markdown-rs/src/visitor/mod.rs +0 -41
- data/vendor/html-to-markdown-rs/src/visitor/traits.rs +0 -370
- data/vendor/html-to-markdown-rs/src/visitor/types.rs +0 -319
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/callbacks/mod.rs +0 -1
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/content.rs +0 -126
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/mod.rs +0 -27
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/state.rs +0 -110
- data/vendor/html-to-markdown-rs/src/visitor_helpers/helpers/traversal.rs +0 -250
- data/vendor/html-to-markdown-rs/src/visitor_helpers.rs +0 -597
- data/vendor/html-to-markdown-rs/src/wrapper/sync.rs +0 -413
- data/vendor/html-to-markdown-rs/src/wrapper/utils.rs +0 -290
- data/vendor/html-to-markdown-rs/src/wrapper.rs +0 -9
- data/vendor/html-to-markdown-rs/tests/br_in_inline_test.rs +0 -87
- data/vendor/html-to-markdown-rs/tests/commonmark_compliance_test.rs +0 -297
- data/vendor/html-to-markdown-rs/tests/djot_output_test.rs +0 -153
- data/vendor/html-to-markdown-rs/tests/exclude_selectors_test.rs +0 -132
- data/vendor/html-to-markdown-rs/tests/integration_test.rs +0 -631
- data/vendor/html-to-markdown-rs/tests/issue_121_regressions.rs +0 -49
- data/vendor/html-to-markdown-rs/tests/issue_127_regressions.rs +0 -58
- data/vendor/html-to-markdown-rs/tests/issue_128_regressions.rs +0 -17
- data/vendor/html-to-markdown-rs/tests/issue_131_regressions.rs +0 -41
- data/vendor/html-to-markdown-rs/tests/issue_134_regressions.rs +0 -40
- data/vendor/html-to-markdown-rs/tests/issue_139_regressions.rs +0 -26
- data/vendor/html-to-markdown-rs/tests/issue_140_regressions.rs +0 -185
- data/vendor/html-to-markdown-rs/tests/issue_143_regressions.rs +0 -100
- data/vendor/html-to-markdown-rs/tests/issue_145_regressions.rs +0 -133
- data/vendor/html-to-markdown-rs/tests/issue_146_regressions.rs +0 -144
- data/vendor/html-to-markdown-rs/tests/issue_176_regressions.rs +0 -62
- data/vendor/html-to-markdown-rs/tests/issue_190_regressions.rs +0 -128
- data/vendor/html-to-markdown-rs/tests/issue_199_regressions.rs +0 -20
- data/vendor/html-to-markdown-rs/tests/issue_200_regressions.rs +0 -62
- data/vendor/html-to-markdown-rs/tests/issue_212_regressions.rs +0 -68
- data/vendor/html-to-markdown-rs/tests/issue_216_217_regressions.rs +0 -87
- data/vendor/html-to-markdown-rs/tests/issue_336_regressions.rs +0 -74
- data/vendor/html-to-markdown-rs/tests/issue_339_regressions.rs +0 -92
- data/vendor/html-to-markdown-rs/tests/issue_347_regressions.rs +0 -154
- data/vendor/html-to-markdown-rs/tests/issue_348_visitor_plain.rs +0 -93
- data/vendor/html-to-markdown-rs/tests/json_ld_script_extraction.rs +0 -44
- data/vendor/html-to-markdown-rs/tests/lists_test.rs +0 -199
- data/vendor/html-to-markdown-rs/tests/plain_output_test.rs +0 -273
- data/vendor/html-to-markdown-rs/tests/preprocessing_tests.rs +0 -61
- data/vendor/html-to-markdown-rs/tests/reference_links_test.rs +0 -169
- data/vendor/html-to-markdown-rs/tests/sectioning_elements_test.rs +0 -137
- data/vendor/html-to-markdown-rs/tests/skip_images_test.rs +0 -522
- data/vendor/html-to-markdown-rs/tests/tables_test.rs +0 -743
- data/vendor/html-to-markdown-rs/tests/test_custom_elements.rs +0 -41
- data/vendor/html-to-markdown-rs/tests/test_issue_187.rs +0 -204
- data/vendor/html-to-markdown-rs/tests/test_issue_218.rs +0 -68
- data/vendor/html-to-markdown-rs/tests/test_issue_277.rs +0 -77
- data/vendor/html-to-markdown-rs/tests/test_max_depth.rs +0 -82
- data/vendor/html-to-markdown-rs/tests/test_nested_simple.rs +0 -45
- data/vendor/html-to-markdown-rs/tests/test_script_style_stripping.rs +0 -396
- data/vendor/html-to-markdown-rs/tests/test_spa_bisect.rs +0 -34
- data/vendor/html-to-markdown-rs/tests/visitor_code_integration_test.rs +0 -121
- data/vendor/html-to-markdown-rs/tests/visitor_integration_test.rs +0 -1190
- data/vendor/html-to-markdown-rs/tests/xml_tables_test.rs +0 -372
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
#![allow(clippy::cast_precision_loss, clippy::cast_sign_loss, clippy::unused_self)]
|
|
2
|
-
//! Text processing utilities for Markdown conversion.
|
|
3
|
-
|
|
4
|
-
use regex::Regex;
|
|
5
|
-
use std::borrow::Cow;
|
|
6
|
-
use std::sync::LazyLock;
|
|
7
|
-
|
|
8
|
-
/// Regex for escaping miscellaneous characters
|
|
9
|
-
static ESCAPE_MISC_RE: LazyLock<Regex> =
|
|
10
|
-
LazyLock::new(|| Regex::new(r"([\\&<`\[\]>~#=+|\-])").expect("valid regex pattern"));
|
|
11
|
-
|
|
12
|
-
/// Regex for escaping numbered lists
|
|
13
|
-
static ESCAPE_NUMBERED_LIST_RE: LazyLock<Regex> =
|
|
14
|
-
LazyLock::new(|| Regex::new(r"([0-9])([.)])").expect("valid regex pattern"));
|
|
15
|
-
|
|
16
|
-
/// Regex for escaping ASCII punctuation (CommonMark spec example 12)
|
|
17
|
-
/// Matches: `! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ \` { | } ~`
|
|
18
|
-
static ESCAPE_ASCII_RE: LazyLock<Regex> =
|
|
19
|
-
LazyLock::new(|| Regex::new(r"([!\x22#$%&\x27()*+,\-./:;<=>?@\[\\\]^_`{|}~])").expect("valid regex pattern"));
|
|
20
|
-
|
|
21
|
-
/// Escape Markdown special characters in text.
|
|
22
|
-
///
|
|
23
|
-
/// # Arguments
|
|
24
|
-
///
|
|
25
|
-
/// * `text` - Text to escape
|
|
26
|
-
/// * `escape_misc` - Escape miscellaneous characters (`\` `&` `<` `` ` `` `[` `>` `~` `#` `=` `+` `|` `-`)
|
|
27
|
-
/// * `escape_asterisks` - Escape asterisks (`*`)
|
|
28
|
-
/// * `escape_underscores` - Escape underscores (`_`)
|
|
29
|
-
/// * `escape_ascii` - Escape all ASCII punctuation (for `CommonMark` spec compliance)
|
|
30
|
-
///
|
|
31
|
-
/// # Returns
|
|
32
|
-
///
|
|
33
|
-
/// Escaped text
|
|
34
|
-
#[allow(clippy::fn_params_excessive_bools)]
|
|
35
|
-
pub fn escape(
|
|
36
|
-
text: &str,
|
|
37
|
-
escape_misc: bool,
|
|
38
|
-
escape_asterisks: bool,
|
|
39
|
-
escape_underscores: bool,
|
|
40
|
-
escape_ascii: bool,
|
|
41
|
-
) -> Cow<'_, str> {
|
|
42
|
-
if text.is_empty() {
|
|
43
|
-
return Cow::Borrowed("");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if !escape_misc && !escape_asterisks && !escape_underscores && !escape_ascii {
|
|
47
|
-
return Cow::Borrowed(text);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if escape_ascii
|
|
51
|
-
&& !text.as_bytes().iter().any(|b| {
|
|
52
|
-
matches!(
|
|
53
|
-
b,
|
|
54
|
-
b'!' | b'"'
|
|
55
|
-
| b'#'
|
|
56
|
-
| b'$'
|
|
57
|
-
| b'%'
|
|
58
|
-
| b'&'
|
|
59
|
-
| b'\''
|
|
60
|
-
| b'('
|
|
61
|
-
| b')'
|
|
62
|
-
| b'*'
|
|
63
|
-
| b'+'
|
|
64
|
-
| b','
|
|
65
|
-
| b'-'
|
|
66
|
-
| b'.'
|
|
67
|
-
| b'/'
|
|
68
|
-
| b':'
|
|
69
|
-
| b';'
|
|
70
|
-
| b'<'
|
|
71
|
-
| b'='
|
|
72
|
-
| b'>'
|
|
73
|
-
| b'?'
|
|
74
|
-
| b'@'
|
|
75
|
-
| b'['
|
|
76
|
-
| b'\\'
|
|
77
|
-
| b']'
|
|
78
|
-
| b'^'
|
|
79
|
-
| b'_'
|
|
80
|
-
| b'`'
|
|
81
|
-
| b'{'
|
|
82
|
-
| b'|'
|
|
83
|
-
| b'}'
|
|
84
|
-
| b'~'
|
|
85
|
-
)
|
|
86
|
-
})
|
|
87
|
-
{
|
|
88
|
-
return Cow::Borrowed(text);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if !escape_ascii && escape_misc && !escape_asterisks && !escape_underscores {
|
|
92
|
-
let needs_misc = text.as_bytes().iter().any(|b| {
|
|
93
|
-
matches!(
|
|
94
|
-
b,
|
|
95
|
-
b'\\' | b'&' | b'<' | b'`' | b'[' | b']' | b'>' | b'~' | b'#' | b'=' | b'+' | b'|' | b'-'
|
|
96
|
-
)
|
|
97
|
-
});
|
|
98
|
-
let needs_numbered = text.as_bytes().iter().any(|b| matches!(b, b'.' | b')'));
|
|
99
|
-
if !needs_misc && !needs_numbered {
|
|
100
|
-
return Cow::Borrowed(text);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let mut result: Cow<'_, str> = Cow::Borrowed(text);
|
|
105
|
-
|
|
106
|
-
if escape_ascii {
|
|
107
|
-
result = match ESCAPE_ASCII_RE.replace_all(result.as_ref(), r"\$1") {
|
|
108
|
-
Cow::Borrowed(_) => result,
|
|
109
|
-
Cow::Owned(s) => Cow::Owned(s),
|
|
110
|
-
};
|
|
111
|
-
return result;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if escape_misc {
|
|
115
|
-
result = match ESCAPE_MISC_RE.replace_all(result.as_ref(), r"\$1") {
|
|
116
|
-
Cow::Borrowed(_) => result,
|
|
117
|
-
Cow::Owned(s) => Cow::Owned(s),
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
result = match ESCAPE_NUMBERED_LIST_RE.replace_all(result.as_ref(), r"$1\$2") {
|
|
121
|
-
Cow::Borrowed(_) => result,
|
|
122
|
-
Cow::Owned(s) => Cow::Owned(s),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if escape_asterisks && result.contains('*') {
|
|
127
|
-
result = Cow::Owned(result.replace('*', r"\*"));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if escape_underscores && result.contains('_') {
|
|
131
|
-
result = Cow::Owned(result.replace('_', r"\_"));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
result
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/// Extract boundary whitespace from text (chomp).
|
|
138
|
-
///
|
|
139
|
-
/// Returns (prefix, suffix, `trimmed_text`) tuple.
|
|
140
|
-
/// Prefix/suffix are " " if original text had leading/trailing whitespace.
|
|
141
|
-
/// However, suffix is "" if the trailing whitespace is only newlines (not spaces/tabs).
|
|
142
|
-
/// This prevents trailing newlines from becoming trailing spaces in the output.
|
|
143
|
-
/// The trimmed text has all leading/trailing whitespace removed.
|
|
144
|
-
#[must_use]
|
|
145
|
-
pub fn chomp(text: &str) -> (&str, &str, &str) {
|
|
146
|
-
if text.is_empty() {
|
|
147
|
-
return ("", "", "");
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
let prefix = if text.starts_with(|c: char| c.is_whitespace()) {
|
|
151
|
-
" "
|
|
152
|
-
} else {
|
|
153
|
-
""
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
let suffix = if text.ends_with("\n\n") || text.ends_with("\r\n\r\n") {
|
|
157
|
-
"\n\n"
|
|
158
|
-
} else if text.ends_with([' ', '\t']) {
|
|
159
|
-
" "
|
|
160
|
-
} else {
|
|
161
|
-
""
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
let trimmed = if suffix == "\n\n" {
|
|
165
|
-
text.trim_end_matches("\n\n").trim_end_matches("\r\n\r\n").trim()
|
|
166
|
-
} else {
|
|
167
|
-
text.trim()
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
(prefix, suffix, trimmed)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/// Normalize whitespace by collapsing consecutive spaces and tabs.
|
|
174
|
-
///
|
|
175
|
-
/// Multiple spaces and tabs are replaced with a single space.
|
|
176
|
-
/// Newlines are preserved.
|
|
177
|
-
/// Unicode spaces are normalized to ASCII spaces.
|
|
178
|
-
///
|
|
179
|
-
/// # Arguments
|
|
180
|
-
///
|
|
181
|
-
/// * `text` - The text to normalize
|
|
182
|
-
///
|
|
183
|
-
/// # Returns
|
|
184
|
-
///
|
|
185
|
-
/// Normalized text with collapsed spaces/tabs but preserved newlines
|
|
186
|
-
#[must_use]
|
|
187
|
-
pub fn normalize_whitespace(text: &str) -> String {
|
|
188
|
-
let mut result = String::with_capacity(text.len());
|
|
189
|
-
let mut prev_was_space = false;
|
|
190
|
-
|
|
191
|
-
for ch in text.chars() {
|
|
192
|
-
let is_space = ch == ' ' || ch == '\t' || is_unicode_space(ch);
|
|
193
|
-
|
|
194
|
-
if is_space {
|
|
195
|
-
if !prev_was_space {
|
|
196
|
-
result.push(' ');
|
|
197
|
-
prev_was_space = true;
|
|
198
|
-
}
|
|
199
|
-
} else {
|
|
200
|
-
result.push(ch);
|
|
201
|
-
prev_was_space = false;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
result
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/// Normalize whitespace in text, returning borrowed or owned result as needed.
|
|
209
|
-
///
|
|
210
|
-
/// This function optimizes memory by returning a borrowed reference when no normalization
|
|
211
|
-
/// is needed, and only allocating a new string when whitespace changes are necessary.
|
|
212
|
-
///
|
|
213
|
-
/// Multiple consecutive spaces, tabs, and Unicode space characters are replaced with
|
|
214
|
-
/// a single ASCII space. Newlines are preserved as-is.
|
|
215
|
-
///
|
|
216
|
-
/// # Arguments
|
|
217
|
-
///
|
|
218
|
-
/// * `text` - The text to normalize
|
|
219
|
-
///
|
|
220
|
-
/// # Returns
|
|
221
|
-
///
|
|
222
|
-
/// `Cow::Borrowed` if text is already normalized, or `Cow::Owned` with normalized text
|
|
223
|
-
#[must_use]
|
|
224
|
-
pub fn normalize_whitespace_cow(text: &str) -> Cow<'_, str> {
|
|
225
|
-
let mut prev_was_space = false;
|
|
226
|
-
|
|
227
|
-
for ch in text.chars() {
|
|
228
|
-
let is_space = ch == ' ' || ch == '\t' || is_unicode_space(ch);
|
|
229
|
-
if is_space {
|
|
230
|
-
if prev_was_space || ch != ' ' {
|
|
231
|
-
return Cow::Owned(normalize_whitespace(text));
|
|
232
|
-
}
|
|
233
|
-
prev_was_space = true;
|
|
234
|
-
} else {
|
|
235
|
-
prev_was_space = false;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
Cow::Borrowed(text)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/// Decode common HTML entities.
|
|
243
|
-
///
|
|
244
|
-
/// Decodes the most common HTML entities to their character equivalents:
|
|
245
|
-
/// - `"` → `"`
|
|
246
|
-
/// - `'` → `'`
|
|
247
|
-
/// - `<` → `<`
|
|
248
|
-
/// - `>` → `>`
|
|
249
|
-
/// - `&` → `&` (must be last to avoid double-decoding)
|
|
250
|
-
///
|
|
251
|
-
/// # Arguments
|
|
252
|
-
///
|
|
253
|
-
/// * `text` - Text containing HTML entities
|
|
254
|
-
///
|
|
255
|
-
/// # Returns
|
|
256
|
-
///
|
|
257
|
-
/// Text with entities decoded
|
|
258
|
-
#[must_use]
|
|
259
|
-
pub fn decode_html_entities(text: &str) -> String {
|
|
260
|
-
html_escape::decode_html_entities(text).into_owned()
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/// Decode HTML entities in text, returning borrowed or owned result as needed.
|
|
264
|
-
///
|
|
265
|
-
/// This function optimizes memory by returning a borrowed reference when no HTML
|
|
266
|
-
/// entities are present, and only allocating a new string when entity decoding
|
|
267
|
-
/// is necessary.
|
|
268
|
-
///
|
|
269
|
-
/// Decodes common HTML entities like:
|
|
270
|
-
/// - `"` → `"`
|
|
271
|
-
/// - `'` → `'`
|
|
272
|
-
/// - `<` → `<`
|
|
273
|
-
/// - `>` → `>`
|
|
274
|
-
/// - `&` → `&` (decoded last to avoid double-decoding)
|
|
275
|
-
///
|
|
276
|
-
/// # Arguments
|
|
277
|
-
///
|
|
278
|
-
/// * `text` - Text potentially containing HTML entities
|
|
279
|
-
///
|
|
280
|
-
/// # Returns
|
|
281
|
-
///
|
|
282
|
-
/// `Cow::Borrowed` if no entities found, or `Cow::Owned` with entities decoded
|
|
283
|
-
#[must_use]
|
|
284
|
-
pub fn decode_html_entities_cow(text: &str) -> Cow<'_, str> {
|
|
285
|
-
if !text.contains('&') {
|
|
286
|
-
return Cow::Borrowed(text);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
html_escape::decode_html_entities(text)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/// Check if a character is a unicode space character.
|
|
293
|
-
///
|
|
294
|
-
/// Includes: non-breaking space, various width spaces, etc.
|
|
295
|
-
const fn is_unicode_space(ch: char) -> bool {
|
|
296
|
-
matches!(
|
|
297
|
-
ch,
|
|
298
|
-
'\u{00A0}'
|
|
299
|
-
| '\u{1680}'
|
|
300
|
-
| '\u{2000}'
|
|
301
|
-
| '\u{2001}'
|
|
302
|
-
| '\u{2002}'
|
|
303
|
-
| '\u{2003}'
|
|
304
|
-
| '\u{2004}'
|
|
305
|
-
| '\u{2005}'
|
|
306
|
-
| '\u{2006}'
|
|
307
|
-
| '\u{2007}'
|
|
308
|
-
| '\u{2008}'
|
|
309
|
-
| '\u{2009}'
|
|
310
|
-
| '\u{200A}'
|
|
311
|
-
| '\u{202F}'
|
|
312
|
-
| '\u{205F}'
|
|
313
|
-
| '\u{3000}'
|
|
314
|
-
)
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
#[cfg(test)]
|
|
318
|
-
mod tests {
|
|
319
|
-
use super::*;
|
|
320
|
-
|
|
321
|
-
#[test]
|
|
322
|
-
fn test_escape_misc() {
|
|
323
|
-
assert_eq!(escape("foo & bar", true, false, false, false), r"foo \& bar");
|
|
324
|
-
assert_eq!(escape("foo [bar]", true, false, false, false), r"foo \[bar\]");
|
|
325
|
-
assert_eq!(escape("1. Item", true, false, false, false), r"1\. Item");
|
|
326
|
-
assert_eq!(escape("1) Item", true, false, false, false), r"1\) Item");
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
#[test]
|
|
330
|
-
fn test_escape_asterisks() {
|
|
331
|
-
assert_eq!(escape("foo * bar", false, true, false, false), r"foo \* bar");
|
|
332
|
-
assert_eq!(escape("**bold**", false, true, false, false), r"\*\*bold\*\*");
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
#[test]
|
|
336
|
-
fn test_escape_underscores() {
|
|
337
|
-
assert_eq!(escape("foo_bar", false, false, true, false), r"foo\_bar");
|
|
338
|
-
assert_eq!(escape("__bold__", false, false, true, false), r"\_\_bold\_\_");
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
#[test]
|
|
342
|
-
fn test_escape_ascii() {
|
|
343
|
-
assert_eq!(escape(r##"!"#$%&"##, false, false, false, true), r#"\!\"\#\$\%\&"#);
|
|
344
|
-
assert_eq!(escape("*+,-./", false, false, false, true), r"\*\+\,\-\.\/");
|
|
345
|
-
assert_eq!(escape("<=>?@", false, false, false, true), r"\<\=\>\?\@");
|
|
346
|
-
assert_eq!(escape(r"[\]^_`", false, false, false, true), r"\[\\\]\^\_\`");
|
|
347
|
-
assert_eq!(escape("{|}~", false, false, false, true), r"\{\|\}\~");
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
#[test]
|
|
351
|
-
fn test_chomp() {
|
|
352
|
-
assert_eq!(chomp(" text "), (" ", " ", "text"));
|
|
353
|
-
assert_eq!(chomp("text"), ("", "", "text"));
|
|
354
|
-
assert_eq!(chomp(" text"), (" ", "", "text"));
|
|
355
|
-
assert_eq!(chomp("text "), ("", " ", "text"));
|
|
356
|
-
assert_eq!(chomp(""), ("", "", ""));
|
|
357
|
-
}
|
|
358
|
-
}
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
//! Structured document tree types aligned with kreuzberg's `DocumentStructure`.
|
|
2
|
-
|
|
3
|
-
use std::collections::HashMap;
|
|
4
|
-
|
|
5
|
-
#[cfg(feature = "serde")]
|
|
6
|
-
use serde::{Deserialize, Serialize};
|
|
7
|
-
|
|
8
|
-
use super::tables::TableGrid;
|
|
9
|
-
|
|
10
|
-
/// A structured document tree representing the semantic content of an HTML document.
|
|
11
|
-
///
|
|
12
|
-
/// Uses a flat node array with index-based parent/child references for efficient traversal.
|
|
13
|
-
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
14
|
-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
15
|
-
pub struct DocumentStructure {
|
|
16
|
-
/// All nodes in document reading order.
|
|
17
|
-
pub nodes: Vec<DocumentNode>,
|
|
18
|
-
/// The source format (always "html" for this crate).
|
|
19
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
20
|
-
pub source_format: Option<String>,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/// A single node in the document tree.
|
|
24
|
-
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
25
|
-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
26
|
-
pub struct DocumentNode {
|
|
27
|
-
/// Deterministic node identifier.
|
|
28
|
-
pub id: String,
|
|
29
|
-
/// The semantic content of this node.
|
|
30
|
-
pub content: NodeContent,
|
|
31
|
-
/// Index of the parent node (None for root nodes).
|
|
32
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
33
|
-
pub parent: Option<u32>,
|
|
34
|
-
/// Indices of child nodes in reading order.
|
|
35
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))]
|
|
36
|
-
pub children: Vec<u32>,
|
|
37
|
-
/// Inline formatting annotations (bold, italic, links, etc.) with byte offsets into the text.
|
|
38
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default))]
|
|
39
|
-
pub annotations: Vec<TextAnnotation>,
|
|
40
|
-
/// Format-specific attributes (e.g. class, id, data-* attributes).
|
|
41
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
42
|
-
pub attributes: Option<HashMap<String, String>>,
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/// The semantic content type of a document node.
|
|
46
|
-
///
|
|
47
|
-
/// Uses internally tagged representation (`"node_type": "heading"`) for JSON serialization.
|
|
48
|
-
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
49
|
-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
50
|
-
#[cfg_attr(feature = "serde", serde(tag = "node_type", rename_all = "snake_case"))]
|
|
51
|
-
pub enum NodeContent {
|
|
52
|
-
/// A heading element (h1-h6).
|
|
53
|
-
Heading {
|
|
54
|
-
/// Heading level (1-6).
|
|
55
|
-
level: u8,
|
|
56
|
-
/// The heading text content.
|
|
57
|
-
text: String,
|
|
58
|
-
},
|
|
59
|
-
/// A paragraph of text.
|
|
60
|
-
Paragraph {
|
|
61
|
-
/// The paragraph text content.
|
|
62
|
-
text: String,
|
|
63
|
-
},
|
|
64
|
-
/// A list container (ordered or unordered). Children are `ListItem` nodes.
|
|
65
|
-
List {
|
|
66
|
-
/// Whether this is an ordered list.
|
|
67
|
-
ordered: bool,
|
|
68
|
-
},
|
|
69
|
-
/// A single list item.
|
|
70
|
-
ListItem {
|
|
71
|
-
/// The list item text content.
|
|
72
|
-
text: String,
|
|
73
|
-
},
|
|
74
|
-
/// A table with structured cell data.
|
|
75
|
-
Table {
|
|
76
|
-
/// The table grid structure.
|
|
77
|
-
grid: TableGrid,
|
|
78
|
-
},
|
|
79
|
-
/// An image element.
|
|
80
|
-
Image {
|
|
81
|
-
/// Alt text or caption.
|
|
82
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
83
|
-
description: Option<String>,
|
|
84
|
-
/// Image source URL.
|
|
85
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
86
|
-
src: Option<String>,
|
|
87
|
-
/// Index into `ConversionResult.images` when image extraction is enabled.
|
|
88
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
89
|
-
image_index: Option<u32>,
|
|
90
|
-
},
|
|
91
|
-
/// A code block or inline code.
|
|
92
|
-
Code {
|
|
93
|
-
/// The code text content.
|
|
94
|
-
text: String,
|
|
95
|
-
/// Programming language (from class="language-*" or similar).
|
|
96
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
97
|
-
language: Option<String>,
|
|
98
|
-
},
|
|
99
|
-
/// A block quote container.
|
|
100
|
-
Quote,
|
|
101
|
-
/// A definition list container.
|
|
102
|
-
DefinitionList,
|
|
103
|
-
/// A definition list entry with term and description.
|
|
104
|
-
DefinitionItem {
|
|
105
|
-
/// The term being defined.
|
|
106
|
-
term: String,
|
|
107
|
-
/// The definition text.
|
|
108
|
-
definition: String,
|
|
109
|
-
},
|
|
110
|
-
/// A raw block preserved as-is (e.g. `<script>`, `<style>` content).
|
|
111
|
-
RawBlock {
|
|
112
|
-
/// The format of the raw content (e.g. "html", "css", "javascript").
|
|
113
|
-
format: String,
|
|
114
|
-
/// The raw content.
|
|
115
|
-
content: String,
|
|
116
|
-
},
|
|
117
|
-
/// A block of key-value metadata pairs (from `<head>` meta tags).
|
|
118
|
-
MetadataBlock {
|
|
119
|
-
/// Key-value metadata pairs.
|
|
120
|
-
entries: Vec<(String, String)>,
|
|
121
|
-
},
|
|
122
|
-
/// A section grouping container (auto-generated from heading hierarchy).
|
|
123
|
-
Group {
|
|
124
|
-
/// Optional section label.
|
|
125
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
126
|
-
label: Option<String>,
|
|
127
|
-
/// The heading level that created this group.
|
|
128
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
129
|
-
heading_level: Option<u8>,
|
|
130
|
-
/// The heading text that created this group.
|
|
131
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
132
|
-
heading_text: Option<String>,
|
|
133
|
-
},
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/// An inline text annotation with byte-range offsets.
|
|
137
|
-
///
|
|
138
|
-
/// Annotations describe formatting (bold, italic, etc.) and links within a node's text content.
|
|
139
|
-
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
140
|
-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
141
|
-
pub struct TextAnnotation {
|
|
142
|
-
/// Start byte offset (inclusive) into the parent node's text.
|
|
143
|
-
pub start: u32,
|
|
144
|
-
/// End byte offset (exclusive) into the parent node's text.
|
|
145
|
-
pub end: u32,
|
|
146
|
-
/// The type of annotation.
|
|
147
|
-
pub kind: AnnotationKind,
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/// The type of an inline text annotation.
|
|
151
|
-
///
|
|
152
|
-
/// Uses internally tagged representation (`"annotation_type": "bold"`) for JSON serialization.
|
|
153
|
-
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
|
154
|
-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
155
|
-
#[cfg_attr(feature = "serde", serde(tag = "annotation_type", rename_all = "snake_case"))]
|
|
156
|
-
pub enum AnnotationKind {
|
|
157
|
-
/// Bold / strong emphasis.
|
|
158
|
-
#[default]
|
|
159
|
-
Bold,
|
|
160
|
-
/// Italic / emphasis.
|
|
161
|
-
Italic,
|
|
162
|
-
/// Underline.
|
|
163
|
-
Underline,
|
|
164
|
-
/// Strikethrough / deleted text.
|
|
165
|
-
Strikethrough,
|
|
166
|
-
/// Inline code.
|
|
167
|
-
Code,
|
|
168
|
-
/// Subscript text.
|
|
169
|
-
Subscript,
|
|
170
|
-
/// Superscript text.
|
|
171
|
-
Superscript,
|
|
172
|
-
/// Highlighted / marked text.
|
|
173
|
-
Highlight,
|
|
174
|
-
/// A hyperlink.
|
|
175
|
-
Link {
|
|
176
|
-
/// The link URL.
|
|
177
|
-
url: String,
|
|
178
|
-
/// Optional link title attribute.
|
|
179
|
-
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
|
180
|
-
title: Option<String>,
|
|
181
|
-
},
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
impl Default for NodeContent {
|
|
185
|
-
fn default() -> Self {
|
|
186
|
-
Self::Heading {
|
|
187
|
-
level: 1,
|
|
188
|
-
text: String::new(),
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
//! Core types for structured HTML extraction results.
|
|
2
|
-
//!
|
|
3
|
-
//! These types are aligned with kreuzberg's `DocumentStructure` model for seamless integration.
|
|
4
|
-
|
|
5
|
-
mod document;
|
|
6
|
-
mod result;
|
|
7
|
-
pub mod structure_builder;
|
|
8
|
-
pub mod structure_collector;
|
|
9
|
-
mod tables;
|
|
10
|
-
mod warnings;
|
|
11
|
-
|
|
12
|
-
pub use document::{AnnotationKind, DocumentNode, DocumentStructure, NodeContent, TextAnnotation};
|
|
13
|
-
pub use result::ConversionResult;
|
|
14
|
-
pub use structure_builder::build_document_structure;
|
|
15
|
-
pub use structure_collector::{StructureCollector, StructureCollectorHandle};
|
|
16
|
-
pub use tables::{GridCell, TableData, TableGrid};
|
|
17
|
-
pub use warnings::{ProcessingWarning, WarningKind};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
//! The primary result type for HTML conversion and extraction.
|
|
2
|
-
|
|
3
|
-
#[cfg(feature = "serde")]
|
|
4
|
-
use serde::{Deserialize, Serialize};
|
|
5
|
-
|
|
6
|
-
use super::document::DocumentStructure;
|
|
7
|
-
use super::tables::TableData;
|
|
8
|
-
use super::warnings::ProcessingWarning;
|
|
9
|
-
|
|
10
|
-
/// The primary result of HTML conversion and extraction.
|
|
11
|
-
///
|
|
12
|
-
/// Contains the converted text output, optional structured document tree,
|
|
13
|
-
/// metadata, extracted tables, images, and processing warnings.
|
|
14
|
-
///
|
|
15
|
-
/// # Example
|
|
16
|
-
///
|
|
17
|
-
/// ```text
|
|
18
|
-
/// use html_to_markdown_rs::{convert, ConversionOptions};
|
|
19
|
-
///
|
|
20
|
-
/// let result = convert("<h1>Hello</h1><p>World</p>", None)?;
|
|
21
|
-
/// assert!(result.content.is_some());
|
|
22
|
-
/// assert!(result.warnings.is_empty());
|
|
23
|
-
/// ```
|
|
24
|
-
#[derive(Debug, Clone, Default)]
|
|
25
|
-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
26
|
-
pub struct ConversionResult {
|
|
27
|
-
/// Converted text output (markdown, djot, or plain text).
|
|
28
|
-
///
|
|
29
|
-
/// `None` when `output_format` is set to `OutputFormat::None`,
|
|
30
|
-
/// indicating extraction-only mode.
|
|
31
|
-
pub content: Option<String>,
|
|
32
|
-
|
|
33
|
-
/// Structured document tree with semantic elements.
|
|
34
|
-
///
|
|
35
|
-
/// Populated when `include_document_structure` is `true` in options.
|
|
36
|
-
pub document: Option<DocumentStructure>,
|
|
37
|
-
|
|
38
|
-
/// Extracted HTML metadata (title, OG, links, images, structured data).
|
|
39
|
-
#[cfg(feature = "metadata")]
|
|
40
|
-
pub metadata: crate::metadata::HtmlMetadata,
|
|
41
|
-
|
|
42
|
-
/// Extracted tables with structured cell data and markdown representation.
|
|
43
|
-
pub tables: Vec<TableData>,
|
|
44
|
-
|
|
45
|
-
/// Extracted inline images (data URIs and SVGs).
|
|
46
|
-
///
|
|
47
|
-
/// Populated when `extract_images` is `true` in options.
|
|
48
|
-
#[cfg(feature = "inline-images")]
|
|
49
|
-
#[cfg_attr(feature = "serde", serde(skip))]
|
|
50
|
-
pub images: Vec<crate::inline_images::InlineImage>,
|
|
51
|
-
|
|
52
|
-
/// Non-fatal processing warnings.
|
|
53
|
-
pub warnings: Vec<ProcessingWarning>,
|
|
54
|
-
}
|