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}