Skip to main content

html_escape/encode/element/
script.rs

1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::str::from_utf8_unchecked;
3#[cfg(feature = "std")]
4use std::io::{self, Write};
5
6macro_rules! parse_script_comment {
7    (@eof $step:ident, $b:block) => {
8        // An unfinished `</script` at the end can still end the element with the text after it.
9        if $step == 8 {
10            $b
11        }
12    };
13    ($e:expr, $step:ident, $b:block, $bc:block) => {
14        match $step {
15            0 => match $e {
16                b'<' => $step = 1,
17                _ => (),
18            },
19            1 => match $e {
20                b'/' => $step = 2,
21                b'!' => $step = 10,
22                b'<' => $step = 1,
23                _ => $step = 0,
24            },
25            2 => match $e {
26                b's' | b'S' => $step = 3,
27                b'<' => $step = 1,
28                _ => $step = 0,
29            },
30            3 => match $e {
31                b'c' | b'C' => $step = 4,
32                b'<' => $step = 1,
33                _ => $step = 0,
34            },
35            4 => match $e {
36                b'r' | b'R' => $step = 5,
37                b'<' => $step = 1,
38                _ => $step = 0,
39            },
40            5 => match $e {
41                b'i' | b'I' => $step = 6,
42                b'<' => $step = 1,
43                _ => $step = 0,
44            },
45            6 => match $e {
46                b'p' | b'P' => $step = 7,
47                b'<' => $step = 1,
48                _ => $step = 0,
49            },
50            7 => match $e {
51                b't' | b'T' => $step = 8,
52                b'<' => $step = 1,
53                _ => $step = 0,
54            },
55            8 => match $e {
56                b'/' | b'>' | 9..=13 | 28..=32 => {
57                    $step = 0;
58                    $b
59                },
60                b'<' => $step = 1,
61                _ => $step = 0,
62            },
63            10 => match $e {
64                b'-' => $step = 11,
65                b'<' => $step = 1,
66                _ => $step = 0,
67            },
68            11 => match $e {
69                b'-' => {
70                    $step = 0;
71                    $bc
72                },
73                b'<' => $step = 1,
74                _ => $step = 0,
75            },
76            _ => unreachable!(),
77        }
78    };
79}
80
81encode_impl! {
82    7;
83    /// The following substring is escaped:
84    ///
85    /// * `</script>` => `<\/script>`
86    /// * `<!--` => `<\!--`
87    ///
88    /// `</script` at the end of the text is also escaped, because the text after it can end the element.
89    /// Pass the whole element text in one call; separate calls do not share parsing state.
90    /// This scans text without parsing JavaScript and may change its meaning.
91    /// Existing escapes are kept, so encoding and decoding may not return the original text.
92    /// This is not a JSON encoder; the `\!` escape is not valid JSON.
93    /// For JSON, first serialize the data as JSON, then replace each literal `<` with `\u003C`.
94    /// Use a quoted text encoder when inserting raw text into a JavaScript string.
95    parse_script_comment;
96    /// Encode text used in the `<script>` element.
97    encode_script;
98    /// Write text used in the `<script>` element to a mutable `String` reference and return the encoded string slice.
99    encode_script_to_string;
100    /// Write text used in the `<script>` element to a mutable `Vec<u8>` reference and return the encoded data slice.
101    encode_script_to_vec;
102    /// Write text used in the `<script>` element to a writer.
103    encode_script_to_writer;
104}
105
106encode_impl! {
107    quoted false, true, false;
108    /// The input is raw text; existing escapes are encoded as text.
109    /// The output is string content and does not include outer quotes.
110    /// Backslashes and `'` are escaped with a backslash.
111    /// `<` and C0 controls use `\xHH` with uppercase hex digits.
112    /// U+2028 and U+2029 use `\u2028` and `\u2029`.
113    /// Use the output in a JavaScript string inside `<script>`, not in a template literal or an HTML attribute.
114    raw_text;
115    /// Encode raw text for a single-quoted JavaScript string inside `<script>`.
116    encode_script_single_quoted_text;
117    /// Encode content of a single-quoted JavaScript string to a mutable `String` and return the new string slice.
118    encode_script_single_quoted_text_to_string;
119    /// Encode content of a single-quoted JavaScript string to a mutable `Vec<u8>` and return the new data slice.
120    encode_script_single_quoted_text_to_vec;
121    /// Encode content of a single-quoted JavaScript string to a writer.
122    encode_script_single_quoted_text_to_writer;
123}
124
125encode_impl! {
126    quoted false, false, true;
127    /// The input is raw text; existing escapes are encoded as text.
128    /// The output is string content and does not include outer quotes.
129    /// Backslashes and `"` are escaped with a backslash.
130    /// `<` and C0 controls use `\xHH` with uppercase hex digits.
131    /// U+2028 and U+2029 use `\u2028` and `\u2029`.
132    /// Use the output in a JavaScript string inside `<script>`, not in a template literal or an HTML attribute.
133    raw_text;
134    /// Encode raw text for a double-quoted JavaScript string inside `<script>`.
135    encode_script_double_quoted_text;
136    /// Encode content of a double-quoted JavaScript string to a mutable `String` and return the new string slice.
137    encode_script_double_quoted_text_to_string;
138    /// Encode content of a double-quoted JavaScript string to a mutable `Vec<u8>` and return the new data slice.
139    encode_script_double_quoted_text_to_vec;
140    /// Encode content of a double-quoted JavaScript string to a writer.
141    encode_script_double_quoted_text_to_writer;
142}
143
144encode_impl! {
145    quoted false, true, true;
146    /// The input is raw text; existing escapes are encoded as text.
147    /// The output is string content and does not include outer quotes.
148    /// Backslashes, `'`, and `"` are escaped with a backslash.
149    /// `<` and C0 controls use `\xHH` with uppercase hex digits.
150    /// U+2028 and U+2029 use `\u2028` and `\u2029`.
151    /// Use the output in a JavaScript string inside `<script>`, not in a template literal or an HTML attribute.
152    raw_text;
153    /// Encode raw text for a single-quoted or double-quoted JavaScript string inside `<script>`.
154    encode_script_quoted_text;
155    /// Encode content of a single-quoted or double-quoted JavaScript string to a mutable `String` and return the new string slice.
156    encode_script_quoted_text_to_string;
157    /// Encode content of a single-quoted or double-quoted JavaScript string to a mutable `Vec<u8>` and return the new data slice.
158    encode_script_quoted_text_to_vec;
159    /// Encode content of a single-quoted or double-quoted JavaScript string to a writer.
160    encode_script_quoted_text_to_writer;
161}