markdown_ai_cite_remove/lib.rs
1//! # markdown-ai-cite-remove
2//!
3//! **Remove AI-generated citations and annotations from Markdown text**
4//!
5//! High-performance Rust library for cleaning ChatGPT, Claude, Perplexity, and other AI markdown
6//! responses. Removes inline citations `[1][2]`, reference links `[1]: https://...`, and
7//! bibliography sections with 100% accuracy.
8//!
9//! ## Quick Start
10//!
11//! ```
12//! use markdown_ai_cite_remove::clean;
13//!
14//! let markdown = "AI research shows promise[1][2].\n\n[1]: https://example.com\n[2]: https://test.com";
15//! let cleaned = clean(markdown);
16//! assert_eq!(cleaned.trim(), "AI research shows promise.");
17//! ```
18//!
19//! ## Features
20//!
21//! - ✅ Remove inline numeric citations `[1][2][3]`
22//! - ✅ Remove named citations `[source:1][ref:2]`
23//! - ✅ Remove reference link lists `[1]: https://...`
24//! - ✅ Remove reference section headers `## References`
25//! - ✅ Remove bibliographic entries
26//! - ✅ Preserve markdown formatting
27//! - ✅ Whitespace normalization
28//! - ✅ Ultra-fast performance (100+ MB/s throughput)
29//!
30//! ## Custom Configuration
31//!
32//! ```
33//! use markdown_ai_cite_remove::{CitationCleaner, CleanerConfig};
34//!
35//! let config = CleanerConfig {
36//! remove_inline_citations: true,
37//! remove_reference_links: true,
38//! ..Default::default()
39//! };
40//!
41//! let cleaner = CitationCleaner::with_config(config);
42//! let cleaned = cleaner.clean("Text with citations[1].");
43//! ```
44
45mod cleaner;
46mod config;
47mod error;
48mod patterns;
49
50pub use cleaner::CitationCleaner;
51pub use config::{CleanerConfig, RemovalMode};
52pub use error::{CleanerError, Result};
53
54/// Main entry point - clean markdown with default settings
55///
56/// # Examples
57///
58/// ```
59/// use markdown_ai_cite_remove::clean;
60///
61/// let input = "Recent research[1][2] shows promise[3].";
62/// let output = clean(input);
63/// assert_eq!(output, "Recent research shows promise.");
64/// ```
65pub fn clean(markdown: &str) -> String {
66 CitationCleaner::new().clean(markdown)
67}
68
69/// Clean markdown with custom configuration
70///
71/// # Examples
72///
73/// ```
74/// use markdown_ai_cite_remove::{clean_with_config, CleanerConfig};
75///
76/// let config = CleanerConfig::inline_only();
77/// let input = "Text[1] here.\n\nSome content.";
78/// let output = clean_with_config(input, config);
79/// assert_eq!(output.trim(), "Text here.\n\nSome content.");
80/// ```
81pub fn clean_with_config(markdown: &str, config: CleanerConfig) -> String {
82 CitationCleaner::with_config(config).clean(markdown)
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 #[test]
90 fn test_clean_basic() {
91 let input = "Text[1] here[2].";
92 let expected = "Text here.";
93 assert_eq!(clean(input), expected);
94 }
95
96 #[test]
97 fn test_clean_with_references() {
98 let input = "Content here.\n\n[1]: https://example.com\n[2]: https://test.com";
99 let expected = "Content here.";
100 assert_eq!(clean(input).trim(), expected);
101 }
102
103 #[test]
104 fn test_clean_preserves_markdown() {
105 let input =
106 "# Heading\n\nSome **bold** text[1] and *italic*[2].\n\n[1]: https://example.com";
107 let expected = "# Heading\n\nSome **bold** text and *italic*.";
108 assert_eq!(clean(input).trim(), expected);
109 }
110
111 #[test]
112 fn test_empty_string() {
113 assert_eq!(clean(""), "");
114 }
115
116 #[test]
117 fn test_no_citations() {
118 let input = "Just regular markdown text.";
119 assert_eq!(clean(input), input);
120 }
121}