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,710 +0,0 @@
|
|
|
1
|
-
//! Main conversion pipeline for HTML to Markdown.
|
|
2
|
-
//!
|
|
3
|
-
//! This module implements the core conversion functions and the recursive tree walker
|
|
4
|
-
//! that transforms HTML DOM nodes into Markdown output.
|
|
5
|
-
|
|
6
|
-
#![allow(
|
|
7
|
-
clippy::too_many_arguments,
|
|
8
|
-
clippy::too_many_lines,
|
|
9
|
-
clippy::trivially_copy_pass_by_ref,
|
|
10
|
-
clippy::items_after_statements
|
|
11
|
-
)]
|
|
12
|
-
|
|
13
|
-
use std::borrow::Cow;
|
|
14
|
-
use std::collections::{BTreeMap, HashSet};
|
|
15
|
-
|
|
16
|
-
use crate::converter::dom_context::DomContext;
|
|
17
|
-
use crate::converter::main_helpers::{
|
|
18
|
-
extract_head_metadata, format_metadata_frontmatter, has_custom_element_tags, repair_with_html5ever,
|
|
19
|
-
trim_line_end_whitespace, trim_trailing_whitespace,
|
|
20
|
-
};
|
|
21
|
-
use crate::converter::plain_text::extract_plain_text;
|
|
22
|
-
use crate::converter::preprocessing_helpers::{has_inline_block_misnest, should_drop_for_preprocessing};
|
|
23
|
-
use crate::converter::utility::caching::build_dom_context;
|
|
24
|
-
use crate::converter::utility::content::normalized_tag_name;
|
|
25
|
-
use crate::converter::utility::preprocessing::{
|
|
26
|
-
normalize_bogus_comment_endings, normalize_split_closing_tags, preprocess_html, strip_hidden_elements,
|
|
27
|
-
strip_script_and_style_tags,
|
|
28
|
-
};
|
|
29
|
-
use crate::converter::utility::serialization::serialize_tag_to_html;
|
|
30
|
-
use crate::options::OutputFormat;
|
|
31
|
-
|
|
32
|
-
use crate::converter::handlers::{handle_blockquote, handle_code, handle_graphic, handle_img, handle_link, handle_pre};
|
|
33
|
-
use crate::error::Result;
|
|
34
|
-
use crate::options::ConversionOptions;
|
|
35
|
-
|
|
36
|
-
use crate::converter::context::{Context, InlineCollectorHandle};
|
|
37
|
-
use crate::types::structure_collector::StructureCollectorHandle;
|
|
38
|
-
|
|
39
|
-
/// Internal implementation of HTML to Markdown conversion.
|
|
40
|
-
///
|
|
41
|
-
/// Returns `(markdown, Option<DocumentStructure>)`. The structure is populated when
|
|
42
|
-
/// `options.include_document_structure == true` and a `structure_collector` handle is provided.
|
|
43
|
-
#[cfg_attr(
|
|
44
|
-
any(not(feature = "inline-images"), not(feature = "metadata"), not(feature = "visitor")),
|
|
45
|
-
allow(unused_variables)
|
|
46
|
-
)]
|
|
47
|
-
#[allow(clippy::too_many_lines)]
|
|
48
|
-
pub fn convert_html_impl(
|
|
49
|
-
html: &str,
|
|
50
|
-
options: &ConversionOptions,
|
|
51
|
-
inline_collector: Option<InlineCollectorHandle>,
|
|
52
|
-
#[cfg(feature = "metadata")] metadata_collector: Option<crate::metadata::MetadataCollectorHandle>,
|
|
53
|
-
#[cfg(not(feature = "metadata"))] _metadata_collector: Option<()>,
|
|
54
|
-
#[cfg(feature = "visitor")] visitor: Option<crate::visitor::VisitorHandle>,
|
|
55
|
-
#[cfg(not(feature = "visitor"))] _visitor: Option<()>,
|
|
56
|
-
structure_collector: Option<StructureCollectorHandle>,
|
|
57
|
-
) -> Result<(
|
|
58
|
-
String,
|
|
59
|
-
Option<crate::types::DocumentStructure>,
|
|
60
|
-
Vec<crate::types::TableData>,
|
|
61
|
-
)> {
|
|
62
|
-
// Strip script and style tags completely to prevent parser confusion from HTML-like content
|
|
63
|
-
// inside script/style elements. This preserves JSON-LD for metadata extraction.
|
|
64
|
-
let stripped = strip_script_and_style_tags(html);
|
|
65
|
-
// Strip elements with the `hidden` attribute before parsing.
|
|
66
|
-
let stripped = strip_hidden_elements(&stripped);
|
|
67
|
-
// Normalise bogus HTML comment endings (`--->`, `---->`, …) that cause the
|
|
68
|
-
// `tl` parser to silently discard all document content that follows them.
|
|
69
|
-
let stripped = normalize_bogus_comment_endings(&stripped);
|
|
70
|
-
// Normalise closing tags whose `>` is on a subsequent line (JSX-style `</a\n>`).
|
|
71
|
-
// The `tl` parser does not handle such end-tags and leaves the element unclosed,
|
|
72
|
-
// causing all subsequent siblings to be absorbed as children.
|
|
73
|
-
let stripped = normalize_split_closing_tags(&stripped);
|
|
74
|
-
let mut preprocessed = preprocess_html(&stripped).into_owned();
|
|
75
|
-
let mut preprocessed_len = preprocessed.len();
|
|
76
|
-
|
|
77
|
-
if has_custom_element_tags(&preprocessed) {
|
|
78
|
-
if let Some(repaired_html) = repair_with_html5ever(&preprocessed) {
|
|
79
|
-
let stripped = strip_script_and_style_tags(&repaired_html);
|
|
80
|
-
let stripped = strip_hidden_elements(&stripped);
|
|
81
|
-
let stripped = normalize_bogus_comment_endings(&stripped);
|
|
82
|
-
let stripped = normalize_split_closing_tags(&stripped);
|
|
83
|
-
let repaired = preprocess_html(&stripped).into_owned();
|
|
84
|
-
preprocessed = repaired;
|
|
85
|
-
preprocessed_len = preprocessed.len();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
let parser_options = tl::ParserOptions::default();
|
|
89
|
-
let mut dom = loop {
|
|
90
|
-
if let Ok(dom) = tl::parse(&preprocessed, parser_options) {
|
|
91
|
-
break dom;
|
|
92
|
-
}
|
|
93
|
-
if let Some(repaired_html) = repair_with_html5ever(&preprocessed) {
|
|
94
|
-
let stripped = strip_script_and_style_tags(&repaired_html);
|
|
95
|
-
let stripped = strip_hidden_elements(&stripped);
|
|
96
|
-
let stripped = normalize_bogus_comment_endings(&stripped);
|
|
97
|
-
let stripped = normalize_split_closing_tags(&stripped);
|
|
98
|
-
preprocessed = preprocess_html(&stripped).into_owned();
|
|
99
|
-
preprocessed_len = preprocessed.len();
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
return Err(crate::error::ConversionError::ParseError(
|
|
103
|
-
"Failed to parse HTML".to_string(),
|
|
104
|
-
));
|
|
105
|
-
};
|
|
106
|
-
let mut parser = dom.parser();
|
|
107
|
-
let mut output = String::with_capacity(preprocessed_len.saturating_add(preprocessed_len / 4));
|
|
108
|
-
|
|
109
|
-
let mut dom_ctx = build_dom_context(&dom, parser, preprocessed_len);
|
|
110
|
-
|
|
111
|
-
// Check for inline-block misnesting and repair if needed
|
|
112
|
-
if has_inline_block_misnest(&dom_ctx, parser) {
|
|
113
|
-
if let Some(repaired_html) = repair_with_html5ever(&preprocessed) {
|
|
114
|
-
// Drop dom to release borrow on preprocessed
|
|
115
|
-
drop(dom);
|
|
116
|
-
let stripped = strip_script_and_style_tags(&repaired_html);
|
|
117
|
-
let stripped = strip_hidden_elements(&stripped);
|
|
118
|
-
let stripped = normalize_bogus_comment_endings(&stripped);
|
|
119
|
-
let stripped = normalize_split_closing_tags(&stripped);
|
|
120
|
-
preprocessed = preprocess_html(&stripped).into_owned();
|
|
121
|
-
preprocessed_len = preprocessed.len();
|
|
122
|
-
// Re-parse with repaired HTML
|
|
123
|
-
dom = tl::parse(&preprocessed, parser_options)
|
|
124
|
-
.map_err(|_| crate::error::ConversionError::ParseError("Failed to parse repaired HTML".to_string()))?;
|
|
125
|
-
parser = dom.parser();
|
|
126
|
-
dom_ctx = build_dom_context(&dom, parser, preprocessed_len);
|
|
127
|
-
output = String::with_capacity(preprocessed_len.saturating_add(preprocessed_len / 4));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Plain text output: run the full pipeline (for metadata + visitor callbacks),
|
|
132
|
-
// then return plain text instead of markdown.
|
|
133
|
-
let is_plain_text = options.output_format == OutputFormat::Plain;
|
|
134
|
-
|
|
135
|
-
let wants_frontmatter = options.extract_metadata && !options.convert_as_inline;
|
|
136
|
-
#[cfg(feature = "metadata")]
|
|
137
|
-
let wants_document = metadata_collector
|
|
138
|
-
.as_ref()
|
|
139
|
-
.is_some_and(|collector| collector.borrow().wants_document());
|
|
140
|
-
#[cfg(not(feature = "metadata"))]
|
|
141
|
-
let wants_document = false;
|
|
142
|
-
|
|
143
|
-
if wants_frontmatter || wants_document {
|
|
144
|
-
let mut head_metadata: Option<BTreeMap<String, String>> = None;
|
|
145
|
-
#[cfg(feature = "metadata")]
|
|
146
|
-
let mut document_lang: Option<String> = None;
|
|
147
|
-
#[cfg(feature = "metadata")]
|
|
148
|
-
let mut document_dir: Option<String> = None;
|
|
149
|
-
|
|
150
|
-
for child_handle in dom.children() {
|
|
151
|
-
if head_metadata.is_none() {
|
|
152
|
-
let metadata = extract_head_metadata(child_handle, parser, options);
|
|
153
|
-
if !metadata.is_empty() {
|
|
154
|
-
head_metadata = Some(metadata);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
#[cfg(feature = "metadata")]
|
|
159
|
-
if wants_document {
|
|
160
|
-
if let Some(tl::Node::Tag(tag)) = child_handle.get(parser) {
|
|
161
|
-
let tag_name = tag.name().as_utf8_str();
|
|
162
|
-
if tag_name == "html" || tag_name == "body" {
|
|
163
|
-
if document_lang.is_none() {
|
|
164
|
-
if let Some(Some(lang_bytes)) = tag.attributes().get("lang") {
|
|
165
|
-
document_lang = Some(lang_bytes.as_utf8_str().to_string());
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
if document_dir.is_none() {
|
|
169
|
-
if let Some(Some(dir_bytes)) = tag.attributes().get("dir") {
|
|
170
|
-
document_dir = Some(dir_bytes.as_utf8_str().to_string());
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if wants_frontmatter {
|
|
179
|
-
if let Some(metadata) = head_metadata.as_ref() {
|
|
180
|
-
if !metadata.is_empty() {
|
|
181
|
-
let metadata_frontmatter = format_metadata_frontmatter(metadata);
|
|
182
|
-
output.push_str(&metadata_frontmatter);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
#[cfg(feature = "metadata")]
|
|
188
|
-
if wants_document {
|
|
189
|
-
if let Some(ref collector) = metadata_collector {
|
|
190
|
-
if let Some(metadata) = head_metadata {
|
|
191
|
-
if !metadata.is_empty() {
|
|
192
|
-
collector.borrow_mut().set_head_metadata(metadata);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
if let Some(lang) = document_lang {
|
|
196
|
-
collector.borrow_mut().set_language(lang);
|
|
197
|
-
}
|
|
198
|
-
if let Some(dir) = document_dir {
|
|
199
|
-
collector.borrow_mut().set_text_direction(dir);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
let reference_collector = if options.link_style == crate::options::LinkStyle::Reference {
|
|
206
|
-
Some(std::rc::Rc::new(std::cell::RefCell::new(
|
|
207
|
-
crate::converter::reference_collector::ReferenceCollector::new(),
|
|
208
|
-
)))
|
|
209
|
-
} else {
|
|
210
|
-
None
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
#[cfg(all(feature = "metadata", feature = "visitor"))]
|
|
214
|
-
let mut ctx = Context::new(
|
|
215
|
-
options,
|
|
216
|
-
inline_collector,
|
|
217
|
-
metadata_collector,
|
|
218
|
-
visitor,
|
|
219
|
-
structure_collector.as_ref().map(std::rc::Rc::clone),
|
|
220
|
-
reference_collector.as_ref().map(std::rc::Rc::clone),
|
|
221
|
-
);
|
|
222
|
-
#[cfg(all(feature = "metadata", not(feature = "visitor")))]
|
|
223
|
-
let mut ctx = Context::new(
|
|
224
|
-
options,
|
|
225
|
-
inline_collector,
|
|
226
|
-
metadata_collector,
|
|
227
|
-
_visitor,
|
|
228
|
-
structure_collector.as_ref().map(std::rc::Rc::clone),
|
|
229
|
-
reference_collector.as_ref().map(std::rc::Rc::clone),
|
|
230
|
-
);
|
|
231
|
-
#[cfg(all(not(feature = "metadata"), feature = "visitor"))]
|
|
232
|
-
let mut ctx = Context::new(
|
|
233
|
-
options,
|
|
234
|
-
inline_collector,
|
|
235
|
-
_metadata_collector,
|
|
236
|
-
visitor,
|
|
237
|
-
structure_collector.as_ref().map(std::rc::Rc::clone),
|
|
238
|
-
reference_collector.as_ref().map(std::rc::Rc::clone),
|
|
239
|
-
);
|
|
240
|
-
#[cfg(all(not(feature = "metadata"), not(feature = "visitor")))]
|
|
241
|
-
let mut ctx = Context::new(
|
|
242
|
-
options,
|
|
243
|
-
inline_collector,
|
|
244
|
-
_metadata_collector,
|
|
245
|
-
_visitor,
|
|
246
|
-
structure_collector.as_ref().map(std::rc::Rc::clone),
|
|
247
|
-
reference_collector.as_ref().map(std::rc::Rc::clone),
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
// Pre-compute node IDs matching exclude_selectors so walk_node can skip them in O(1).
|
|
251
|
-
// Invalid or unsupported selectors are silently skipped.
|
|
252
|
-
if !options.exclude_selectors.is_empty() {
|
|
253
|
-
let mut excluded: HashSet<u32> = HashSet::new();
|
|
254
|
-
for selector in &options.exclude_selectors {
|
|
255
|
-
if let Some(iter) = dom.query_selector(selector) {
|
|
256
|
-
for handle in iter {
|
|
257
|
-
excluded.insert(handle.get_inner());
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
ctx.set_excluded_node_ids(excluded);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
for child_handle in dom.children() {
|
|
265
|
-
walk_node(child_handle, parser, &mut output, options, &ctx, 0, &dom_ctx);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
#[cfg(feature = "visitor")]
|
|
269
|
-
if let Some(err) = ctx.visitor_error.borrow().as_ref() {
|
|
270
|
-
return Err(crate::error::ConversionError::Visitor(err.clone()));
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Drop ctx before unwrapping the structure collector Rc — ctx holds a cloned Rc
|
|
274
|
-
// reference to the same collector, and Rc::try_unwrap requires exactly one reference.
|
|
275
|
-
drop(ctx);
|
|
276
|
-
|
|
277
|
-
// Append reference-style link definitions if any were collected
|
|
278
|
-
if let Some(rc) = reference_collector {
|
|
279
|
-
if let Ok(collector) = std::rc::Rc::try_unwrap(rc) {
|
|
280
|
-
let ref_section = collector.into_inner().finish();
|
|
281
|
-
if !ref_section.is_empty() {
|
|
282
|
-
let trimmed_len = output.trim_end_matches('\n').len();
|
|
283
|
-
output.truncate(trimmed_len);
|
|
284
|
-
output.push_str("\n\n");
|
|
285
|
-
output.push_str(&ref_section);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// If plain text was requested, discard the markdown output and return plain text.
|
|
291
|
-
// The full pipeline was still run above so that metadata + visitor callbacks fire.
|
|
292
|
-
if is_plain_text {
|
|
293
|
-
let plain = extract_plain_text(&dom, parser, options);
|
|
294
|
-
let (document, tables) = finish_structure_collector(structure_collector);
|
|
295
|
-
return Ok((plain, document, tables));
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
trim_line_end_whitespace(&mut output);
|
|
299
|
-
let trimmed = output.trim_end_matches('\n');
|
|
300
|
-
let markdown = if trimmed.is_empty() {
|
|
301
|
-
String::new()
|
|
302
|
-
} else {
|
|
303
|
-
format!("{trimmed}\n")
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
// Finish the structure collector if present.
|
|
307
|
-
let (document, tables) = finish_structure_collector(structure_collector);
|
|
308
|
-
|
|
309
|
-
Ok((markdown, document, tables))
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/// Consume the structure collector and return the [`DocumentStructure`] and extracted
|
|
313
|
-
/// [`TableData`] entries. Returns `(None, vec![])` when no collector was provided.
|
|
314
|
-
fn finish_structure_collector(
|
|
315
|
-
sc: Option<StructureCollectorHandle>,
|
|
316
|
-
) -> (Option<crate::types::DocumentStructure>, Vec<crate::types::TableData>) {
|
|
317
|
-
match sc.and_then(|rc| std::rc::Rc::try_unwrap(rc).ok()) {
|
|
318
|
-
Some(cell) => {
|
|
319
|
-
let (doc, tables) = cell.into_inner().finish();
|
|
320
|
-
(Some(doc), tables)
|
|
321
|
-
}
|
|
322
|
-
None => (None, Vec::new()),
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// has_more_than_one_char moved to main_helpers
|
|
327
|
-
// is_inline_element available from utility::content
|
|
328
|
-
|
|
329
|
-
/// Recursively walk DOM nodes and convert to Markdown.
|
|
330
|
-
#[allow(clippy::only_used_in_recursion)]
|
|
331
|
-
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
332
|
-
#[allow(clippy::cast_possible_truncation)]
|
|
333
|
-
pub fn walk_node(
|
|
334
|
-
node_handle: &tl::NodeHandle,
|
|
335
|
-
parser: &tl::Parser,
|
|
336
|
-
output: &mut String,
|
|
337
|
-
options: &ConversionOptions,
|
|
338
|
-
ctx: &Context,
|
|
339
|
-
depth: usize,
|
|
340
|
-
dom_ctx: &DomContext,
|
|
341
|
-
) {
|
|
342
|
-
let Some(node) = node_handle.get(parser) else { return };
|
|
343
|
-
|
|
344
|
-
if let Some(max) = options.max_depth {
|
|
345
|
-
if depth >= max {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
match node {
|
|
351
|
-
tl::Node::Raw(bytes) => {
|
|
352
|
-
let raw = bytes.as_utf8_str();
|
|
353
|
-
crate::converter::text_node::process_text_node(
|
|
354
|
-
raw.as_ref(),
|
|
355
|
-
node_handle,
|
|
356
|
-
parser,
|
|
357
|
-
output,
|
|
358
|
-
options,
|
|
359
|
-
ctx,
|
|
360
|
-
depth,
|
|
361
|
-
dom_ctx,
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
tl::Node::Tag(tag) => {
|
|
366
|
-
let tag_name = match dom_ctx.tag_info(node_handle.get_inner(), parser) {
|
|
367
|
-
Some(info) => Cow::Borrowed(info.name.as_str()),
|
|
368
|
-
None => normalized_tag_name(tag.name().as_utf8_str()),
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
#[cfg(feature = "visitor")]
|
|
372
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
373
|
-
use crate::converter::visitor_hooks::{VisitAction, handle_visitor_element_start};
|
|
374
|
-
|
|
375
|
-
let action = handle_visitor_element_start(
|
|
376
|
-
visitor_handle,
|
|
377
|
-
tag_name.as_ref(),
|
|
378
|
-
node_handle,
|
|
379
|
-
tag,
|
|
380
|
-
parser,
|
|
381
|
-
output,
|
|
382
|
-
ctx,
|
|
383
|
-
depth,
|
|
384
|
-
dom_ctx,
|
|
385
|
-
);
|
|
386
|
-
|
|
387
|
-
match action {
|
|
388
|
-
VisitAction::Continue => {}
|
|
389
|
-
VisitAction::Skip => return,
|
|
390
|
-
VisitAction::Custom => return,
|
|
391
|
-
VisitAction::Error => return,
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
#[cfg(feature = "visitor")]
|
|
396
|
-
let visitor_is_active = ctx.visitor.is_some();
|
|
397
|
-
#[cfg(not(feature = "visitor"))]
|
|
398
|
-
let visitor_is_active = false;
|
|
399
|
-
|
|
400
|
-
if !visitor_is_active && should_drop_for_preprocessing(tag_name.as_ref(), tag, options) {
|
|
401
|
-
trim_trailing_whitespace(output);
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Drop elements matching exclude_selectors, including all their descendants.
|
|
406
|
-
if !ctx.excluded_node_ids.is_empty() && ctx.excluded_node_ids.contains(&node_handle.get_inner()) {
|
|
407
|
-
trim_trailing_whitespace(output);
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if ctx.strip_tags.contains(tag_name.as_ref()) {
|
|
412
|
-
let children = tag.children();
|
|
413
|
-
{
|
|
414
|
-
for child_handle in children.top().iter() {
|
|
415
|
-
walk_node(child_handle, parser, output, options, ctx, depth + 1, dom_ctx);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if ctx.preserve_tags.contains(tag_name.as_ref()) {
|
|
422
|
-
let html = serialize_tag_to_html(node_handle, parser);
|
|
423
|
-
output.push_str(&html);
|
|
424
|
-
return;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
#[cfg(feature = "metadata")]
|
|
428
|
-
if matches!(tag_name.as_ref(), "html" | "head" | "body") && ctx.metadata_wants_document {
|
|
429
|
-
if let Some(ref collector) = ctx.metadata_collector {
|
|
430
|
-
let mut c = collector.borrow_mut();
|
|
431
|
-
|
|
432
|
-
if let Some(lang) = tag.attributes().get("lang").flatten() {
|
|
433
|
-
c.set_language(lang.as_utf8_str().to_string());
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if let Some(dir) = tag.attributes().get("dir").flatten() {
|
|
437
|
-
c.set_text_direction(dir.as_utf8_str().to_string());
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
#[cfg_attr(not(feature = "visitor"), allow(unused_variables))]
|
|
443
|
-
let element_output_start = output.len();
|
|
444
|
-
|
|
445
|
-
match tag_name.as_ref() {
|
|
446
|
-
"h1" | "h2" | "h3" | "h4" | "h5" | "h6" => {
|
|
447
|
-
crate::converter::block::heading::handle(
|
|
448
|
-
&tag_name,
|
|
449
|
-
node_handle,
|
|
450
|
-
parser,
|
|
451
|
-
output,
|
|
452
|
-
options,
|
|
453
|
-
ctx,
|
|
454
|
-
depth,
|
|
455
|
-
dom_ctx,
|
|
456
|
-
);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
"p" => {
|
|
460
|
-
crate::converter::block::paragraph::handle(
|
|
461
|
-
node_handle,
|
|
462
|
-
parser,
|
|
463
|
-
output,
|
|
464
|
-
options,
|
|
465
|
-
ctx,
|
|
466
|
-
depth,
|
|
467
|
-
dom_ctx,
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// All inline elements routed to inline dispatcher
|
|
472
|
-
"strong" | "b" | "em" | "i" | "mark" | "del" | "s" | "ins" | "u" | "small" | "sub" | "sup" | "kbd"
|
|
473
|
-
| "samp" | "var" | "dfn" | "abbr" | "ruby" | "rb" | "rt" | "rp" | "rtc" | "span" => {
|
|
474
|
-
crate::converter::inline::dispatch_inline_handler(
|
|
475
|
-
&tag_name,
|
|
476
|
-
node_handle,
|
|
477
|
-
parser,
|
|
478
|
-
output,
|
|
479
|
-
options,
|
|
480
|
-
ctx,
|
|
481
|
-
depth,
|
|
482
|
-
dom_ctx,
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
"a" => handle_link(node_handle, tag, parser, output, options, ctx, depth, dom_ctx),
|
|
487
|
-
"img" => handle_img(node_handle, tag, parser, output, options, ctx, depth, dom_ctx),
|
|
488
|
-
"graphic" => handle_graphic(node_handle, tag, parser, output, options, ctx, depth, dom_ctx),
|
|
489
|
-
"code" => handle_code(node_handle, tag, parser, output, options, ctx, depth, dom_ctx),
|
|
490
|
-
"pre" => handle_pre(node_handle, tag, parser, output, options, ctx, depth, dom_ctx),
|
|
491
|
-
"blockquote" => handle_blockquote(node_handle, tag, parser, output, options, ctx, depth, dom_ctx),
|
|
492
|
-
|
|
493
|
-
"time" | "data" => {
|
|
494
|
-
crate::converter::block::container::handle_passthrough(
|
|
495
|
-
node_handle,
|
|
496
|
-
parser,
|
|
497
|
-
output,
|
|
498
|
-
options,
|
|
499
|
-
ctx,
|
|
500
|
-
depth,
|
|
501
|
-
dom_ctx,
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// Noop elements that produce no output
|
|
506
|
-
"wbr" | "thead" | "tbody" | "tfoot" | "tr" | "th" | "td" | "source" => {
|
|
507
|
-
crate::converter::block::container::handle_noop(
|
|
508
|
-
node_handle,
|
|
509
|
-
parser,
|
|
510
|
-
output,
|
|
511
|
-
options,
|
|
512
|
-
ctx,
|
|
513
|
-
depth,
|
|
514
|
-
dom_ctx,
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
"br" => crate::converter::block::line_break::handle(
|
|
519
|
-
node_handle,
|
|
520
|
-
parser,
|
|
521
|
-
output,
|
|
522
|
-
options,
|
|
523
|
-
ctx,
|
|
524
|
-
depth,
|
|
525
|
-
dom_ctx,
|
|
526
|
-
),
|
|
527
|
-
"hr" => crate::converter::block::horizontal_rule::handle(
|
|
528
|
-
node_handle,
|
|
529
|
-
parser,
|
|
530
|
-
output,
|
|
531
|
-
options,
|
|
532
|
-
ctx,
|
|
533
|
-
depth,
|
|
534
|
-
dom_ctx,
|
|
535
|
-
),
|
|
536
|
-
"div" => {
|
|
537
|
-
crate::converter::block::div::handle(node_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
538
|
-
}
|
|
539
|
-
"caption" => crate::converter::block::table::handle_caption(
|
|
540
|
-
node_handle,
|
|
541
|
-
parser,
|
|
542
|
-
output,
|
|
543
|
-
options,
|
|
544
|
-
ctx,
|
|
545
|
-
depth,
|
|
546
|
-
dom_ctx,
|
|
547
|
-
),
|
|
548
|
-
"table" => crate::converter::block::table::handle_table_with_context(
|
|
549
|
-
node_handle,
|
|
550
|
-
parser,
|
|
551
|
-
output,
|
|
552
|
-
options,
|
|
553
|
-
ctx,
|
|
554
|
-
dom_ctx,
|
|
555
|
-
depth,
|
|
556
|
-
),
|
|
557
|
-
|
|
558
|
-
// List elements routed to list dispatcher
|
|
559
|
-
"ul" | "ol" | "li" | "dl" | "dt" | "dd" => {
|
|
560
|
-
crate::converter::list::dispatch_list_handler(
|
|
561
|
-
&tag_name,
|
|
562
|
-
node_handle,
|
|
563
|
-
tag,
|
|
564
|
-
parser,
|
|
565
|
-
output,
|
|
566
|
-
options,
|
|
567
|
-
ctx,
|
|
568
|
-
depth,
|
|
569
|
-
dom_ctx,
|
|
570
|
-
);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
// Sectioning elements routed to semantic dispatcher
|
|
574
|
-
"article" | "section" | "nav" | "aside" | "header" | "footer" | "main" => {
|
|
575
|
-
crate::converter::semantic::dispatch_semantic_handler(
|
|
576
|
-
&tag_name,
|
|
577
|
-
node_handle,
|
|
578
|
-
parser,
|
|
579
|
-
output,
|
|
580
|
-
options,
|
|
581
|
-
ctx,
|
|
582
|
-
depth,
|
|
583
|
-
dom_ctx,
|
|
584
|
-
);
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// Quote element routed to semantic dispatcher
|
|
588
|
-
"q" => {
|
|
589
|
-
crate::converter::semantic::dispatch_semantic_handler(
|
|
590
|
-
&tag_name,
|
|
591
|
-
node_handle,
|
|
592
|
-
parser,
|
|
593
|
-
output,
|
|
594
|
-
options,
|
|
595
|
-
ctx,
|
|
596
|
-
depth,
|
|
597
|
-
dom_ctx,
|
|
598
|
-
);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Figure elements routed to semantic dispatcher
|
|
602
|
-
"figure" | "figcaption" => {
|
|
603
|
-
crate::converter::semantic::dispatch_semantic_handler(
|
|
604
|
-
&tag_name,
|
|
605
|
-
node_handle,
|
|
606
|
-
parser,
|
|
607
|
-
output,
|
|
608
|
-
options,
|
|
609
|
-
ctx,
|
|
610
|
-
depth,
|
|
611
|
-
dom_ctx,
|
|
612
|
-
);
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// Semantic interactive elements routed to semantic dispatcher
|
|
616
|
-
"details" | "summary" | "dialog" | "menu" => {
|
|
617
|
-
crate::converter::semantic::dispatch_semantic_handler(
|
|
618
|
-
&tag_name,
|
|
619
|
-
node_handle,
|
|
620
|
-
parser,
|
|
621
|
-
output,
|
|
622
|
-
options,
|
|
623
|
-
ctx,
|
|
624
|
-
depth,
|
|
625
|
-
dom_ctx,
|
|
626
|
-
);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// Media elements routed to media dispatcher
|
|
630
|
-
"audio" | "video" | "picture" | "iframe" | "svg" | "math" => {
|
|
631
|
-
crate::converter::media::dispatch_media_handler(
|
|
632
|
-
&tag_name,
|
|
633
|
-
node_handle,
|
|
634
|
-
parser,
|
|
635
|
-
output,
|
|
636
|
-
options,
|
|
637
|
-
ctx,
|
|
638
|
-
depth,
|
|
639
|
-
dom_ctx,
|
|
640
|
-
);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Form elements routed to form dispatcher
|
|
644
|
-
"form" | "fieldset" | "legend" | "label" | "input" | "textarea" | "select" | "option" | "optgroup"
|
|
645
|
-
| "button" | "progress" | "meter" | "output" | "datalist" => {
|
|
646
|
-
crate::converter::form::dispatch_form_handler(
|
|
647
|
-
&tag_name,
|
|
648
|
-
node_handle,
|
|
649
|
-
parser,
|
|
650
|
-
output,
|
|
651
|
-
options,
|
|
652
|
-
ctx,
|
|
653
|
-
depth,
|
|
654
|
-
dom_ctx,
|
|
655
|
-
);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
// Metadata elements routed to metadata handler
|
|
659
|
-
"head" | "script" | "style" => {
|
|
660
|
-
crate::converter::metadata::handle(
|
|
661
|
-
&tag_name,
|
|
662
|
-
node_handle,
|
|
663
|
-
parser,
|
|
664
|
-
output,
|
|
665
|
-
options,
|
|
666
|
-
ctx,
|
|
667
|
-
depth,
|
|
668
|
-
dom_ctx,
|
|
669
|
-
);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
"body" | "html" => {
|
|
673
|
-
crate::converter::block::container::handle_structural_container(
|
|
674
|
-
node_handle,
|
|
675
|
-
parser,
|
|
676
|
-
output,
|
|
677
|
-
options,
|
|
678
|
-
ctx,
|
|
679
|
-
depth,
|
|
680
|
-
dom_ctx,
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
_ => {
|
|
685
|
-
crate::converter::block::unknown::handle(node_handle, parser, output, options, ctx, depth, dom_ctx);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
#[cfg(feature = "visitor")]
|
|
690
|
-
if let Some(ref visitor_handle) = ctx.visitor {
|
|
691
|
-
use crate::converter::visitor_hooks::handle_visitor_element_end;
|
|
692
|
-
|
|
693
|
-
handle_visitor_element_end(
|
|
694
|
-
visitor_handle,
|
|
695
|
-
tag_name.as_ref(),
|
|
696
|
-
node_handle,
|
|
697
|
-
tag,
|
|
698
|
-
parser,
|
|
699
|
-
output,
|
|
700
|
-
element_output_start,
|
|
701
|
-
ctx,
|
|
702
|
-
depth,
|
|
703
|
-
dom_ctx,
|
|
704
|
-
);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
tl::Node::Comment(_) => {}
|
|
709
|
-
}
|
|
710
|
-
}
|