html-to-markdown 3.4.0 → 3.6.0.pre.rc.24
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,144 +0,0 @@
|
|
|
1
|
-
#![allow(missing_docs)]
|
|
2
|
-
|
|
3
|
-
use html_to_markdown_rs::ConversionOptions;
|
|
4
|
-
|
|
5
|
-
#[test]
|
|
6
|
-
fn test_strip_tags_prevents_metadata_extraction() {
|
|
7
|
-
let html = r#"<!DOCTYPE html>
|
|
8
|
-
<html>
|
|
9
|
-
<head>
|
|
10
|
-
<title>Test Document</title>
|
|
11
|
-
<meta name="author" content="John Doe">
|
|
12
|
-
<meta name="description" content="A test document">
|
|
13
|
-
<meta property="og:title" content="Test OG Title">
|
|
14
|
-
</head>
|
|
15
|
-
<body>
|
|
16
|
-
<p>Main content here</p>
|
|
17
|
-
</body>
|
|
18
|
-
</html>"#;
|
|
19
|
-
|
|
20
|
-
let options = ConversionOptions {
|
|
21
|
-
extract_metadata: true,
|
|
22
|
-
strip_tags: vec!["meta".to_string()],
|
|
23
|
-
..Default::default()
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
let result = convert(html, Some(options)).unwrap();
|
|
27
|
-
|
|
28
|
-
assert!(
|
|
29
|
-
result.contains("Main content here"),
|
|
30
|
-
"Body content should be preserved: {result}"
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
assert!(
|
|
34
|
-
result.contains("title: Test Document"),
|
|
35
|
-
"Title should still be extracted in frontmatter: {result}"
|
|
36
|
-
);
|
|
37
|
-
|
|
38
|
-
assert!(
|
|
39
|
-
!result.contains("meta-author"),
|
|
40
|
-
"meta-author should NOT be in frontmatter when strip_tags=['meta']: {result}"
|
|
41
|
-
);
|
|
42
|
-
assert!(
|
|
43
|
-
!result.contains("meta-description"),
|
|
44
|
-
"meta-description should NOT be in frontmatter when strip_tags=['meta']: {result}"
|
|
45
|
-
);
|
|
46
|
-
assert!(
|
|
47
|
-
!result.contains("meta-og-title"),
|
|
48
|
-
"meta-og-title should NOT be in frontmatter when strip_tags=['meta']: {result}"
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
#[test]
|
|
53
|
-
fn test_strip_tags_title_prevents_extraction() {
|
|
54
|
-
let html = r#"<!DOCTYPE html>
|
|
55
|
-
<html>
|
|
56
|
-
<head>
|
|
57
|
-
<title>Should Be Stripped</title>
|
|
58
|
-
<meta name="author" content="Jane Smith">
|
|
59
|
-
<meta name="keywords" content="test, demo">
|
|
60
|
-
</head>
|
|
61
|
-
<body>
|
|
62
|
-
<h1>Document Heading</h1>
|
|
63
|
-
<p>Some content</p>
|
|
64
|
-
</body>
|
|
65
|
-
</html>"#;
|
|
66
|
-
|
|
67
|
-
let options = ConversionOptions {
|
|
68
|
-
extract_metadata: true,
|
|
69
|
-
strip_tags: vec!["title".to_string()],
|
|
70
|
-
..Default::default()
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
let result = convert(html, Some(options)).unwrap();
|
|
74
|
-
|
|
75
|
-
assert!(
|
|
76
|
-
result.contains("Document Heading") && result.contains("Some content"),
|
|
77
|
-
"Body content should be preserved: {result}"
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
assert!(
|
|
81
|
-
result.contains("meta-author"),
|
|
82
|
-
"meta-author should still be extracted when only title is stripped: {result}"
|
|
83
|
-
);
|
|
84
|
-
assert!(
|
|
85
|
-
result.contains("meta-keywords"),
|
|
86
|
-
"meta-keywords should still be extracted when only title is stripped: {result}"
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
assert!(
|
|
90
|
-
!result.contains("title: Should Be Stripped"),
|
|
91
|
-
"title should NOT be in frontmatter when strip_tags=['title']: {result}"
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
#[test]
|
|
96
|
-
fn test_preserve_tags_prevents_metadata_extraction() {
|
|
97
|
-
let html = r#"<!DOCTYPE html>
|
|
98
|
-
<html>
|
|
99
|
-
<head>
|
|
100
|
-
<title>Preserved Title</title>
|
|
101
|
-
<meta name="viewport" content="width=device-width">
|
|
102
|
-
<meta name="author" content="Test Author">
|
|
103
|
-
</head>
|
|
104
|
-
<body>
|
|
105
|
-
<div>
|
|
106
|
-
<p>Body content</p>
|
|
107
|
-
</div>
|
|
108
|
-
</body>
|
|
109
|
-
</html>"#;
|
|
110
|
-
|
|
111
|
-
let options = ConversionOptions {
|
|
112
|
-
extract_metadata: true,
|
|
113
|
-
preserve_tags: vec!["meta".to_string()],
|
|
114
|
-
..Default::default()
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
let result = convert(html, Some(options)).unwrap();
|
|
118
|
-
|
|
119
|
-
assert!(
|
|
120
|
-
result.contains("Body content"),
|
|
121
|
-
"Body content should be preserved: {result}"
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
assert!(
|
|
125
|
-
result.contains("title: Preserved Title"),
|
|
126
|
-
"title should still be extracted in frontmatter: {result}"
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
assert!(
|
|
130
|
-
!result.contains("meta-viewport"),
|
|
131
|
-
"meta-viewport should NOT be in YAML frontmatter when preserve_tags=['meta']: {result}"
|
|
132
|
-
);
|
|
133
|
-
assert!(
|
|
134
|
-
!result.contains("meta-author"),
|
|
135
|
-
"meta-author should NOT be in YAML frontmatter when preserve_tags=['meta']: {result}"
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
fn convert(
|
|
140
|
-
html: &str,
|
|
141
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
142
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
143
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
144
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
#![allow(missing_docs)]
|
|
2
|
-
|
|
3
|
-
//! Regression tests for issue #176: Newlines not preserved with adjacent blockquotes
|
|
4
|
-
|
|
5
|
-
#[test]
|
|
6
|
-
fn test_strong_blockquote_strong_newlines() {
|
|
7
|
-
fn convert(
|
|
8
|
-
html: &str,
|
|
9
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
10
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
11
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Test case from issue #176: strong + blockquote + strong
|
|
15
|
-
let html = r"<strong>2. Point two</strong><blockquote>Option Explicit
|
|
16
|
-
Sub Test()
|
|
17
|
-
' code here
|
|
18
|
-
End Function</blockquote><strong>3. Point three</strong>";
|
|
19
|
-
|
|
20
|
-
let markdown = convert(html, None).unwrap();
|
|
21
|
-
|
|
22
|
-
println!("Actual output:\n{markdown}");
|
|
23
|
-
println!("---");
|
|
24
|
-
|
|
25
|
-
// Should have blank lines separating elements
|
|
26
|
-
assert!(
|
|
27
|
-
markdown.contains("**2. Point two**\n\n>"),
|
|
28
|
-
"Should have blank line between strong and blockquote. Got: {markdown:?}"
|
|
29
|
-
);
|
|
30
|
-
assert!(
|
|
31
|
-
markdown.contains("End Function\n\n**3. Point three**"),
|
|
32
|
-
"Should have blank line between blockquote and next strong. Got: {markdown:?}"
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
#[test]
|
|
37
|
-
fn test_paragraph_blockquote_paragraph_newlines() {
|
|
38
|
-
fn convert(
|
|
39
|
-
html: &str,
|
|
40
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
41
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
42
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Control test: p + blockquote + p should work correctly
|
|
46
|
-
let html = r"<p>First paragraph</p><blockquote>A quote</blockquote><p>Second paragraph</p>";
|
|
47
|
-
|
|
48
|
-
let markdown = convert(html, None).unwrap();
|
|
49
|
-
|
|
50
|
-
println!("Actual output:\n{markdown}");
|
|
51
|
-
|
|
52
|
-
// Should have single newline before blockquote (CommonMark spec)
|
|
53
|
-
// and blank line after blockquote
|
|
54
|
-
assert!(
|
|
55
|
-
markdown.contains("First paragraph\n>"),
|
|
56
|
-
"Should have single newline between p and blockquote (CommonMark compliance)"
|
|
57
|
-
);
|
|
58
|
-
assert!(
|
|
59
|
-
markdown.contains("A quote\n\n"),
|
|
60
|
-
"Should have blank line after blockquote"
|
|
61
|
-
);
|
|
62
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
//! Regression coverage for issue #190.
|
|
2
|
-
|
|
3
|
-
fn convert(
|
|
4
|
-
html: &str,
|
|
5
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
6
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
7
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
use std::fs;
|
|
11
|
-
use std::path::PathBuf;
|
|
12
|
-
|
|
13
|
-
use html_to_markdown_rs::{CodeBlockStyle, ConversionOptions};
|
|
14
|
-
|
|
15
|
-
fn fixture_path(name: &str) -> PathBuf {
|
|
16
|
-
[
|
|
17
|
-
env!("CARGO_MANIFEST_DIR"),
|
|
18
|
-
"../../test_documents/html/issues/gh-190",
|
|
19
|
-
name,
|
|
20
|
-
]
|
|
21
|
-
.iter()
|
|
22
|
-
.collect()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
fn read_fixture_lossy(name: &str) -> String {
|
|
26
|
-
let bytes = fs::read(fixture_path(name)).expect("read issue #190 fixture");
|
|
27
|
-
String::from_utf8_lossy(&bytes).into_owned()
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
fn decode_utf16_without_bom(bytes: &[u8]) -> String {
|
|
31
|
-
let mut even_nul = 0usize;
|
|
32
|
-
let mut odd_nul = 0usize;
|
|
33
|
-
for (idx, &byte) in bytes.iter().enumerate() {
|
|
34
|
-
if byte == 0 {
|
|
35
|
-
if idx % 2 == 0 {
|
|
36
|
-
even_nul += 1;
|
|
37
|
-
} else {
|
|
38
|
-
odd_nul += 1;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
let is_little_endian = odd_nul >= even_nul;
|
|
44
|
-
let mut units = Vec::with_capacity(bytes.len() / 2);
|
|
45
|
-
let mut chunks = bytes.chunks_exact(2);
|
|
46
|
-
for chunk in &mut chunks {
|
|
47
|
-
let unit = if is_little_endian {
|
|
48
|
-
u16::from_le_bytes([chunk[0], chunk[1]])
|
|
49
|
-
} else {
|
|
50
|
-
u16::from_be_bytes([chunk[0], chunk[1]])
|
|
51
|
-
};
|
|
52
|
-
units.push(unit);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
String::from_utf16_lossy(&units)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
#[test]
|
|
59
|
-
fn test_code_block_dedent_handles_unicode_whitespace() {
|
|
60
|
-
let nbsp = '\u{00A0}';
|
|
61
|
-
let html = format!("<pre><code> msg = String()\n{nbsp}msg = String()\n</code></pre>");
|
|
62
|
-
let options = ConversionOptions {
|
|
63
|
-
code_block_style: CodeBlockStyle::Backticks,
|
|
64
|
-
..Default::default()
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
let markdown = convert(&html, Some(options)).expect("conversion should succeed");
|
|
68
|
-
|
|
69
|
-
assert!(markdown.contains("msg = String()"));
|
|
70
|
-
assert!(!markdown.contains(nbsp));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
#[test]
|
|
74
|
-
fn test_convert_strips_nul_bytes() {
|
|
75
|
-
let html = "a\0b";
|
|
76
|
-
let markdown = convert(html, None).expect("conversion should succeed");
|
|
77
|
-
|
|
78
|
-
assert_eq!(markdown, "ab\n");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
#[test]
|
|
82
|
-
fn converts_all_issue_190_fixtures_except_known_utf16_binary() {
|
|
83
|
-
let fixtures = [
|
|
84
|
-
"firsteigen.html",
|
|
85
|
-
"vipaarontours.html",
|
|
86
|
-
"ozonekorea.html",
|
|
87
|
-
"mitrade.html",
|
|
88
|
-
"plusblog.html",
|
|
89
|
-
"maxkim.html",
|
|
90
|
-
"insight.html",
|
|
91
|
-
"flex2025.html",
|
|
92
|
-
"flex2021.html",
|
|
93
|
-
"kimbrain.html",
|
|
94
|
-
"rbloggers.html",
|
|
95
|
-
"sjsu.html",
|
|
96
|
-
];
|
|
97
|
-
|
|
98
|
-
for name in fixtures {
|
|
99
|
-
let html = read_fixture_lossy(name);
|
|
100
|
-
let markdown =
|
|
101
|
-
convert(&html, None).unwrap_or_else(|err| panic!("fixture {name} should convert cleanly: {err}"));
|
|
102
|
-
assert!(!markdown.trim().is_empty(), "fixture {name} produced empty markdown");
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
#[test]
|
|
107
|
-
fn converts_sjsu_fixture_when_lossy_utf8_is_auto_decoded() {
|
|
108
|
-
let bytes = fs::read(fixture_path("sjsu.html")).expect("read sjsu fixture bytes");
|
|
109
|
-
let raw_html = String::from_utf8_lossy(&bytes).into_owned();
|
|
110
|
-
|
|
111
|
-
let markdown = convert(&raw_html, None).expect("lossy UTF-16 HTML should be recovered and converted");
|
|
112
|
-
assert!(
|
|
113
|
-
markdown.contains("pipeline") || markdown.contains("Pipeline"),
|
|
114
|
-
"auto-decoded sjsu fixture should contain expected content"
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
#[test]
|
|
119
|
-
fn converts_sjsu_fixture_when_decoded_as_utf16() {
|
|
120
|
-
let bytes = fs::read(fixture_path("sjsu.html")).expect("read sjsu fixture bytes");
|
|
121
|
-
let decoded_html = decode_utf16_without_bom(&bytes);
|
|
122
|
-
|
|
123
|
-
let markdown = convert(&decoded_html, None).expect("decoded UTF-16 HTML should convert");
|
|
124
|
-
assert!(
|
|
125
|
-
markdown.contains("pipeline") || markdown.contains("Pipeline"),
|
|
126
|
-
"decoded sjsu fixture should contain expected content"
|
|
127
|
-
);
|
|
128
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
//! Regression coverage for issue #199.
|
|
2
|
-
|
|
3
|
-
fn convert(
|
|
4
|
-
html: &str,
|
|
5
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
6
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
7
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
#[test]
|
|
11
|
-
fn test_link_label_is_not_truncated() {
|
|
12
|
-
let label = "a".repeat(600);
|
|
13
|
-
let html = format!(r#"<a href="https://example.com">{label}</a>"#);
|
|
14
|
-
|
|
15
|
-
let markdown = convert(&html, None).expect("conversion should succeed");
|
|
16
|
-
let expected = format!("[{label}](https://example.com)");
|
|
17
|
-
|
|
18
|
-
assert!(markdown.contains(&expected));
|
|
19
|
-
assert!(!markdown.contains('…'));
|
|
20
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
//! Regression coverage for issues #200 and #214.
|
|
2
|
-
|
|
3
|
-
fn convert(
|
|
4
|
-
html: &str,
|
|
5
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
6
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
7
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
#[test]
|
|
11
|
-
fn test_definition_list_spacing_consistency() {
|
|
12
|
-
let html1 = r#"
|
|
13
|
-
<div>
|
|
14
|
-
<dl>
|
|
15
|
-
<dt>Tags:</dt>
|
|
16
|
-
<dd>
|
|
17
|
-
<ul>
|
|
18
|
-
<li>
|
|
19
|
-
<a href="https://site.com">php</a>
|
|
20
|
-
</li>
|
|
21
|
-
<li>
|
|
22
|
-
<a href="https://site.com/search/">closure</a>
|
|
23
|
-
</li>
|
|
24
|
-
</ul>
|
|
25
|
-
<button type="button">Add tags</button>
|
|
26
|
-
</dd>
|
|
27
|
-
</dl>
|
|
28
|
-
</div>
|
|
29
|
-
"#;
|
|
30
|
-
|
|
31
|
-
let html2 = r#"<div><dl><dt>Tags:</dt><dd><ul><li><a href="https://site.com">php</a></li><li><a href="https://site.com/search/">closure</a></li></ul><button type="button">Add tags</button></dd></dl></div>"#;
|
|
32
|
-
|
|
33
|
-
let markdown1 = convert(html1, None).expect("conversion should succeed");
|
|
34
|
-
let markdown2 = convert(html2, None).expect("conversion should succeed");
|
|
35
|
-
|
|
36
|
-
assert_eq!(markdown1, markdown2);
|
|
37
|
-
assert!(markdown1.contains("Tags:"));
|
|
38
|
-
assert!(markdown1.contains("[php]"));
|
|
39
|
-
assert!(markdown1.contains("[closure]"));
|
|
40
|
-
assert!(markdown1.contains("Add tags"));
|
|
41
|
-
// Ensure no Pandoc definition list colon prefix is introduced
|
|
42
|
-
assert!(!markdown1.contains(": "));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/// Regression test for issue #214: colon introduced into text from dd elements.
|
|
46
|
-
#[test]
|
|
47
|
-
fn test_definition_list_no_colon_prefix() {
|
|
48
|
-
let html = r#"<dl>
|
|
49
|
-
<dt id="canRequestFocus" class="property inherited">
|
|
50
|
-
<span class="name"><a href="material/InkResponse/canRequestFocus.html">canRequestFocus</a></span>
|
|
51
|
-
<span class="signature">→ <a href="dart-core/bool-class.html">bool</a></span>
|
|
52
|
-
</dt>
|
|
53
|
-
<dd class="inherited">
|
|
54
|
-
If true, this widget may request the primary focus.
|
|
55
|
-
<div class="features"><span class="feature">final</span><span class="feature">inherited</span></div>
|
|
56
|
-
</dd>
|
|
57
|
-
</dl>"#;
|
|
58
|
-
let markdown = convert(html, None).expect("conversion should succeed");
|
|
59
|
-
assert!(markdown.contains("If true, this widget may request the primary focus."));
|
|
60
|
-
// The dd content must not be prefixed with ": " (Pandoc definition list syntax)
|
|
61
|
-
assert!(!markdown.contains(": If true"));
|
|
62
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
#![allow(missing_docs)]
|
|
2
|
-
|
|
3
|
-
fn convert(
|
|
4
|
-
html: &str,
|
|
5
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
6
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
7
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/// Regression test for <https://github.com/kreuzberg-dev/html-to-markdown/issues/212>
|
|
11
|
-
///
|
|
12
|
-
/// When `\n` precedes an `<a>` tag inside a `<p>`, the whitespace was
|
|
13
|
-
/// inconsistently handled between the first and subsequent paragraphs.
|
|
14
|
-
/// The bug was stateful: identical HTML structures produced different
|
|
15
|
-
/// results depending on their position in the document.
|
|
16
|
-
#[test]
|
|
17
|
-
fn consistent_whitespace_before_link_across_paragraphs_issue_212() {
|
|
18
|
-
let html = r#"<p>text before
|
|
19
|
-
<a href="https://example.com">the link</a>
|
|
20
|
-
after</p>
|
|
21
|
-
<p>text before
|
|
22
|
-
<a href="https://example.com">the link</a>
|
|
23
|
-
after</p>"#;
|
|
24
|
-
|
|
25
|
-
let result = convert(html, None).unwrap();
|
|
26
|
-
assert_eq!(
|
|
27
|
-
result,
|
|
28
|
-
"text before [the link](https://example.com) after\n\ntext before [the link](https://example.com) after\n"
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/// Same bug but with three paragraphs to ensure no accumulation effects.
|
|
33
|
-
#[test]
|
|
34
|
-
fn consistent_whitespace_three_paragraphs_issue_212() {
|
|
35
|
-
let html = r#"<p>click
|
|
36
|
-
<a href="/a">here</a></p>
|
|
37
|
-
<p>click
|
|
38
|
-
<a href="/b">here</a></p>
|
|
39
|
-
<p>click
|
|
40
|
-
<a href="/c">here</a></p>"#;
|
|
41
|
-
|
|
42
|
-
let result = convert(html, None).unwrap();
|
|
43
|
-
assert_eq!(result, "click [here](/a)\n\nclick [here](/b)\n\nclick [here](/c)\n");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/// Verify the fix doesn't break whitespace between text nodes without links.
|
|
47
|
-
#[test]
|
|
48
|
-
fn newline_before_inline_elements_consistent_issue_212() {
|
|
49
|
-
let html = r"<p>before
|
|
50
|
-
<strong>bold</strong> after</p>
|
|
51
|
-
<p>before
|
|
52
|
-
<strong>bold</strong> after</p>";
|
|
53
|
-
|
|
54
|
-
let result = convert(html, None).unwrap();
|
|
55
|
-
assert_eq!(result, "before **bold** after\n\nbefore **bold** after\n");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/// Verify with `<em>` tags across multiple paragraphs.
|
|
59
|
-
#[test]
|
|
60
|
-
fn newline_before_em_across_paragraphs_issue_212() {
|
|
61
|
-
let html = r"<p>some text
|
|
62
|
-
<em>emphasized</em> end</p>
|
|
63
|
-
<p>some text
|
|
64
|
-
<em>emphasized</em> end</p>";
|
|
65
|
-
|
|
66
|
-
let result = convert(html, None).unwrap();
|
|
67
|
-
assert_eq!(result, "some text *emphasized* end\n\nsome text *emphasized* end\n");
|
|
68
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
//! Regression tests for issues #216 and #217.
|
|
2
|
-
//!
|
|
3
|
-
//! Both issues report a panic at `text_node.rs:191`:
|
|
4
|
-
//! "byte index N is out of bounds of \`\`"
|
|
5
|
-
//!
|
|
6
|
-
//! Root cause: When inline handlers (strong, em, etc.) collect children into a
|
|
7
|
-
//! fresh String buffer while inheriting a parent context with `block_content_start`
|
|
8
|
-
//! set by a paragraph handler, the index points into the wrong buffer.
|
|
9
|
-
|
|
10
|
-
fn convert(
|
|
11
|
-
html: &str,
|
|
12
|
-
opts: Option<html_to_markdown_rs::ConversionOptions>,
|
|
13
|
-
) -> html_to_markdown_rs::error::Result<String> {
|
|
14
|
-
html_to_markdown_rs::convert(html, opts).map(|r| r.content.unwrap_or_default())
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/// Minimal reproducer: a <details> containing a <p> with <strong> inside.
|
|
18
|
-
/// The <details> handler collects into a fresh buffer, the <p> sets
|
|
19
|
-
/// `block_content_start`, and the <strong> handler creates yet another fresh
|
|
20
|
-
/// buffer — causing the index to be out of bounds.
|
|
21
|
-
#[test]
|
|
22
|
-
fn test_issue_216_217_details_paragraph_strong_no_panic() {
|
|
23
|
-
let html = r"
|
|
24
|
-
<div>some preceding content</div>
|
|
25
|
-
<details>
|
|
26
|
-
<summary>Summary text</summary>
|
|
27
|
-
<p><strong>Bold text inside details paragraph
|
|
28
|
-
</strong></p>
|
|
29
|
-
</details>
|
|
30
|
-
";
|
|
31
|
-
|
|
32
|
-
let result = convert(html, None);
|
|
33
|
-
assert!(result.is_ok());
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/// Same issue can occur with emphasis inside a paragraph inside details.
|
|
37
|
-
#[test]
|
|
38
|
-
fn test_issue_216_217_details_paragraph_em_no_panic() {
|
|
39
|
-
let html = r"
|
|
40
|
-
<div>some preceding content</div>
|
|
41
|
-
<details>
|
|
42
|
-
<summary>Summary</summary>
|
|
43
|
-
<p><em>Italic text inside details paragraph
|
|
44
|
-
</em></p>
|
|
45
|
-
</details>
|
|
46
|
-
";
|
|
47
|
-
|
|
48
|
-
let result = convert(html, None);
|
|
49
|
-
assert!(result.is_ok());
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/// The panic can also occur with nested inline elements inside paragraphs
|
|
53
|
-
/// collected by any handler that creates a fresh buffer.
|
|
54
|
-
#[test]
|
|
55
|
-
fn test_issue_216_217_nested_strong_in_paragraph_no_panic() {
|
|
56
|
-
let html = r"
|
|
57
|
-
<details>
|
|
58
|
-
<p>Some text <strong>bold text with trailing newline
|
|
59
|
-
</strong> more text</p>
|
|
60
|
-
</details>
|
|
61
|
-
";
|
|
62
|
-
|
|
63
|
-
let result = convert(html, None);
|
|
64
|
-
assert!(result.is_ok());
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/// Test with the actual structure pattern from the reported URL.
|
|
68
|
-
#[test]
|
|
69
|
-
fn test_issue_216_217_complex_details_structure() {
|
|
70
|
-
let html = r#"
|
|
71
|
-
<div class="content">
|
|
72
|
-
<section>
|
|
73
|
-
<details>
|
|
74
|
-
<summary>Stratégie adaptation</summary>
|
|
75
|
-
<p><strong>Risque élevé pour les populations
|
|
76
|
-
</strong></p>
|
|
77
|
-
<p>Description du risque avec des détails supplémentaires.</p>
|
|
78
|
-
</details>
|
|
79
|
-
</section>
|
|
80
|
-
</div>
|
|
81
|
-
"#;
|
|
82
|
-
|
|
83
|
-
let result = convert(html, None);
|
|
84
|
-
assert!(result.is_ok());
|
|
85
|
-
let md = result.unwrap();
|
|
86
|
-
assert!(md.contains("Risque"));
|
|
87
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#![allow(missing_docs)]
|
|
2
|
-
|
|
3
|
-
//! Regression tests for issue #336: content after a table is silently truncated when an
|
|
4
|
-
//! unclosed `<p>` appears inside a `<td>` without a closing `</p>`.
|
|
5
|
-
//!
|
|
6
|
-
//! The `tl` parser mishandles malformed Word/Outlook HTML (produced by Microsoft Word's
|
|
7
|
-
//! HTML export) where a `<p>` tag inside a `<td>` is not properly closed before the
|
|
8
|
-
//! `</td>` end tag. When the unclosed `<p>` appears in a table cell, `tl` treats all
|
|
9
|
-
//! subsequent sibling elements — including other `<td>` cells and all post-table content —
|
|
10
|
-
//! as descendants of that `<p>`.
|
|
11
|
-
//!
|
|
12
|
-
//! The most visible symptom: any `<p>`, `<h2>`, or other element that comes **after** the
|
|
13
|
-
//! closing `</table>` tag gets swallowed into the last table cell and is never emitted as
|
|
14
|
-
//! top-level document content, causing the output to appear truncated.
|
|
15
|
-
//!
|
|
16
|
-
//! Triggered by the `<td><p class='MsoNormal'> </td>` pattern that appears 34 times
|
|
17
|
-
//! in `ms-fscc.html` — specifically when that pattern is the *first* `<td>` in a row.
|
|
18
|
-
|
|
19
|
-
fn convert(html: &str) -> String {
|
|
20
|
-
html_to_markdown_rs::convert(html, None)
|
|
21
|
-
.expect("conversion should not fail")
|
|
22
|
-
.content
|
|
23
|
-
.unwrap_or_default()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/// Minimal reproduction: a table with two rows each having an unclosed `<p>` as the first
|
|
27
|
-
/// `<td>`. The `<p>SectionAfterTable</p>` that follows MUST appear in the output.
|
|
28
|
-
///
|
|
29
|
-
/// Without the fix, `tl` nests the post-table `<p>` inside the last table `<td>`, so the
|
|
30
|
-
/// converter either drops it (blank-table fast-return) or renders it inline inside a table
|
|
31
|
-
/// cell — in both cases it is absent as a top-level paragraph.
|
|
32
|
-
#[test]
|
|
33
|
-
fn test_content_after_table_not_dropped_when_td_has_unclosed_p() {
|
|
34
|
-
let html = r"<table>
|
|
35
|
-
<tr>
|
|
36
|
-
<td width=1><p class='MsoNormal'> </td>
|
|
37
|
-
<td>Row1Data</td>
|
|
38
|
-
</tr>
|
|
39
|
-
<tr>
|
|
40
|
-
<td width=1><p class='MsoNormal'> </td>
|
|
41
|
-
<td>Row2Data</td>
|
|
42
|
-
</tr>
|
|
43
|
-
</table>
|
|
44
|
-
<p>SectionAfterTable</p>";
|
|
45
|
-
|
|
46
|
-
let result = convert(html);
|
|
47
|
-
assert!(
|
|
48
|
-
result.contains("SectionAfterTable"),
|
|
49
|
-
"Content after the table must not be swallowed into the table DOM. Got:\n{result}"
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/// Headings and subsequent sections after such a table must also be preserved.
|
|
54
|
-
#[test]
|
|
55
|
-
fn test_headings_after_table_with_msonormal_p_in_td_are_preserved() {
|
|
56
|
-
let html = r"<table>
|
|
57
|
-
<tr>
|
|
58
|
-
<td width=1><p class='MsoNormal'> </td>
|
|
59
|
-
<td>Some data</td>
|
|
60
|
-
</tr>
|
|
61
|
-
</table>
|
|
62
|
-
<h2>Section 2.4.22</h2>
|
|
63
|
-
<p>This section describes something important.</p>";
|
|
64
|
-
|
|
65
|
-
let result = convert(html);
|
|
66
|
-
assert!(
|
|
67
|
-
result.contains("Section 2.4.22"),
|
|
68
|
-
"Heading after the table must appear in the output. Got:\n{result}"
|
|
69
|
-
);
|
|
70
|
-
assert!(
|
|
71
|
-
result.contains("This section describes something important"),
|
|
72
|
-
"Paragraph after the heading must appear. Got:\n{result}"
|
|
73
|
-
);
|
|
74
|
-
}
|