1#![forbid(unsafe_code)]
20#![allow(clippy::default_trait_access)]
21#![allow(clippy::module_name_repetitions)]
22#![allow(clippy::redundant_pub_crate)]
23#![deny(rustdoc::broken_intra_doc_links)]
24#![cfg_attr(not(any(feature = "integration_test", test)), warn(missing_docs))]
25#![cfg_attr(any(feature = "integration_test", test), allow(unnameable_types))]
26
27#[macro_use]
28mod base;
29
30#[macro_use]
31mod html;
32
33#[macro_use]
34mod rewriter;
35
36mod memory;
37mod parser;
38mod rewritable_units;
39mod transform_stream;
40
41use cfg_if::cfg_if;
42
43pub use self::rewriter::{
44 AsciiCompatibleEncoding, CommentHandler, DoctypeHandler, DocumentContentHandlers,
45 ElementContentHandlers, ElementHandler, EndHandler, EndTagHandler, HandlerResult, HandlerTypes,
46 HtmlRewriter, LocalHandlerTypes, MemorySettings, RewriteStrSettings, Settings, TextHandler,
47 rewrite_str,
48};
49pub use self::selectors_vm::Selector;
50pub use self::transform_stream::OutputSink;
51
52pub mod send {
58 pub use crate::rewriter::{
59 CommentHandlerSend as CommentHandler, DoctypeHandlerSend as DoctypeHandler,
60 ElementHandlerSend as ElementHandler, EndHandlerSend as EndHandler,
61 EndTagHandlerSend as EndTagHandler, TextHandlerSend as TextHandler,
62 };
63 pub use crate::rewriter::{IntoHandler, SendHandlerTypes};
64
65 pub type HtmlRewriter<'handlers, O> = crate::HtmlRewriter<'handlers, O, SendHandlerTypes>;
67 pub type Settings<'handlers, 'selectors> =
69 crate::Settings<'handlers, 'selectors, SendHandlerTypes>;
70 pub type RewriteStrSettings<'handlers, 'selectors> =
72 crate::RewriteStrSettings<'handlers, 'selectors, SendHandlerTypes>;
73
74 pub type ElementContentHandlers<'h> = crate::ElementContentHandlers<'h, SendHandlerTypes>;
76 pub type DocumentContentHandlers<'h> = crate::DocumentContentHandlers<'h, SendHandlerTypes>;
78
79 pub type Element<'rewriter, 'input_token> =
81 crate::rewritable_units::Element<'rewriter, 'input_token, SendHandlerTypes>;
82}
83
84pub mod errors {
86 pub use super::memory::MemoryLimitExceededError;
87 pub use super::parser::ParsingAmbiguityError;
88 pub use super::rewritable_units::{
89 AttributeNameError, CommentTextError, TagNameError, Utf8Error,
90 };
91 pub use super::rewriter::RewritingError;
92 pub use super::selectors_vm::SelectorError;
93}
94
95pub mod html_content {
97 pub use super::rewritable_units::{
98 Attribute, Comment, ContentType, Doctype, DocumentEnd, Element, EndTag, StartTag,
99 StreamingHandler, StreamingHandlerSink, TextChunk, UserData,
100 };
101
102 pub use super::base::SourceLocation;
103 pub use super::html::TextType;
104}
105
106#[cfg(any(test, feature = "integration_test"))]
107pub mod test_utils {
108 use encoding_rs::*;
109
110 pub static ASCII_COMPATIBLE_ENCODINGS: [&Encoding; 36] = [
111 BIG5,
112 EUC_JP,
113 EUC_KR,
114 GB18030,
115 GBK,
116 IBM866,
117 ISO_8859_2,
118 ISO_8859_3,
119 ISO_8859_4,
120 ISO_8859_5,
121 ISO_8859_6,
122 ISO_8859_7,
123 ISO_8859_8,
124 ISO_8859_8_I,
125 ISO_8859_10,
126 ISO_8859_13,
127 ISO_8859_14,
128 ISO_8859_15,
129 ISO_8859_16,
130 KOI8_R,
131 KOI8_U,
132 MACINTOSH,
133 SHIFT_JIS,
134 UTF_8,
135 WINDOWS_874,
136 WINDOWS_1250,
137 WINDOWS_1251,
138 WINDOWS_1252,
139 WINDOWS_1253,
140 WINDOWS_1254,
141 WINDOWS_1255,
142 WINDOWS_1256,
143 WINDOWS_1257,
144 WINDOWS_1258,
145 X_MAC_CYRILLIC,
146 X_USER_DEFINED,
147 ];
148
149 pub static NON_ASCII_COMPATIBLE_ENCODINGS: [&Encoding; 4] =
150 [UTF_16BE, UTF_16LE, ISO_2022_JP, REPLACEMENT];
151
152 pub struct Output {
153 bytes: Vec<u8>,
154 encoding: &'static Encoding,
155 finalizing_chunk_received: bool,
156 }
157
158 impl Output {
159 #[must_use]
160 #[inline]
161 pub fn new(encoding: &'static Encoding) -> Self {
162 Self {
163 bytes: Vec::default(),
164 encoding,
165 finalizing_chunk_received: false,
166 }
167 }
168
169 #[inline]
170 #[track_caller]
171 pub fn push(&mut self, chunk: &[u8]) {
172 if chunk.is_empty() {
173 self.finalizing_chunk_received = true;
174 } else {
175 assert!(
176 !self.finalizing_chunk_received,
177 "Chunk written to the output after the finalizing chunk."
178 );
179
180 self.bytes.extend_from_slice(chunk);
181 }
182 }
183 }
184
185 impl From<Output> for String {
186 #[inline]
187 #[track_caller]
188 fn from(output: Output) -> Self {
189 assert!(
190 output.finalizing_chunk_received,
191 "Finalizing chunk for the output hasn't been received."
192 );
193
194 output
195 .encoding
196 .decode_without_bom_handling(&output.bytes)
197 .0
198 .into_owned()
199 }
200 }
201}
202
203cfg_if! {
204 if #[cfg(feature = "integration_test")] {
205 pub mod selectors_vm;
206
207 pub use self::base::SharedEncoding;
208
209 pub use self::transform_stream::{
210 StartTagHandlingResult, TransformController, TransformStream,
211 TransformStreamSettings
212 };
213
214 pub use self::rewritable_units::{
215 EndTag, Serialize, StartTag, Token, TokenCaptureFlags,
216 };
217
218 pub use self::memory::SharedMemoryLimiter;
219 pub use self::html::{LocalName, LocalNameHash, Tag, Namespace};
220 } else {
221 mod selectors_vm;
222 }
223}