1pub const HLJS_DARK_CSS: &[u8] = include_bytes!("../templates/hljs.dark.11.12.0.css");
8pub const HLJS_ATOM_ONE_DARK_CSS: &[u8] =
10 include_bytes!("../templates/hljs.atom-one-dark.11.12.0.css");
11
12pub const HLJS_JS: &[u8] = include_bytes!("../templates/hljs.11.12.0.js");
14
15pub const HLJS_LANG_BASH: &[u8] = include_bytes!("../templates/hljs.lang.bash.11.12.0.js");
17pub const HLJS_LANG_CSS: &[u8] = include_bytes!("../templates/hljs.lang.css.11.12.0.js");
18pub const HLJS_LANG_DOCKERFILE: &[u8] =
19 include_bytes!("../templates/hljs.lang.dockerfile.11.12.0.js");
20pub const HLJS_LANG_GO: &[u8] = include_bytes!("../templates/hljs.lang.go.11.12.0.js");
21pub const HLJS_LANG_JAVA: &[u8] = include_bytes!("../templates/hljs.lang.java.11.12.0.js");
22pub const HLJS_LANG_JAVASCRIPT: &[u8] =
23 include_bytes!("../templates/hljs.lang.javascript.11.12.0.js");
24pub const HLJS_LANG_JSON: &[u8] = include_bytes!("../templates/hljs.lang.json.11.12.0.js");
25pub const HLJS_LANG_MARKDOWN: &[u8] = include_bytes!("../templates/hljs.lang.markdown.11.12.0.js");
26pub const HLJS_LANG_NIX: &[u8] = include_bytes!("../templates/hljs.lang.nix.11.12.0.js");
27pub const HLJS_LANG_PYTHON: &[u8] = include_bytes!("../templates/hljs.lang.python.11.12.0.js");
28pub const HLJS_LANG_RUBY: &[u8] = include_bytes!("../templates/hljs.lang.ruby.11.12.0.js");
29pub const HLJS_LANG_RUST: &[u8] = include_bytes!("../templates/hljs.lang.rust.11.12.0.js");
30pub const HLJS_LANG_SCALA: &[u8] = include_bytes!("../templates/hljs.lang.scala.11.12.0.js");
31pub const HLJS_LANG_SQL: &[u8] = include_bytes!("../templates/hljs.lang.sql.11.12.0.js");
32pub const HLJS_LANG_TYPESCRIPT: &[u8] =
33 include_bytes!("../templates/hljs.lang.typescript.11.12.0.js");
34pub const HLJS_LANG_XML: &[u8] = include_bytes!("../templates/hljs.lang.xml.11.12.0.js");
35pub const HLJS_LANG_YAML: &[u8] = include_bytes!("../templates/hljs.lang.yaml.11.12.0.js");
36
37pub const HLJS_FILES: &[(&str, &[u8], &str)] = &[
41 (
42 "/hljs.atom-one-dark.css",
43 HLJS_ATOM_ONE_DARK_CSS,
44 "text/css",
45 ),
46 ("/hljs.js", HLJS_JS, "application/javascript"),
47 (
48 "/hljs.lang.bash.js",
49 HLJS_LANG_BASH,
50 "application/javascript",
51 ),
52 ("/hljs.lang.css.js", HLJS_LANG_CSS, "application/javascript"),
53 (
54 "/hljs.lang.dockerfile.js",
55 HLJS_LANG_DOCKERFILE,
56 "application/javascript",
57 ),
58 ("/hljs.lang.go.js", HLJS_LANG_GO, "application/javascript"),
59 (
60 "/hljs.lang.java.js",
61 HLJS_LANG_JAVA,
62 "application/javascript",
63 ),
64 (
65 "/hljs.lang.javascript.js",
66 HLJS_LANG_JAVASCRIPT,
67 "application/javascript",
68 ),
69 (
70 "/hljs.lang.json.js",
71 HLJS_LANG_JSON,
72 "application/javascript",
73 ),
74 (
75 "/hljs.lang.markdown.js",
76 HLJS_LANG_MARKDOWN,
77 "application/javascript",
78 ),
79 ("/hljs.lang.nix.js", HLJS_LANG_NIX, "application/javascript"),
80 (
81 "/hljs.lang.python.js",
82 HLJS_LANG_PYTHON,
83 "application/javascript",
84 ),
85 (
86 "/hljs.lang.ruby.js",
87 HLJS_LANG_RUBY,
88 "application/javascript",
89 ),
90 (
91 "/hljs.lang.rust.js",
92 HLJS_LANG_RUST,
93 "application/javascript",
94 ),
95 (
96 "/hljs.lang.scala.js",
97 HLJS_LANG_SCALA,
98 "application/javascript",
99 ),
100 ("/hljs.lang.sql.js", HLJS_LANG_SQL, "application/javascript"),
101 (
102 "/hljs.lang.typescript.js",
103 HLJS_LANG_TYPESCRIPT,
104 "application/javascript",
105 ),
106 ("/hljs.lang.xml.js", HLJS_LANG_XML, "application/javascript"),
107 (
108 "/hljs.lang.yaml.js",
109 HLJS_LANG_YAML,
110 "application/javascript",
111 ),
112];
113
114pub fn language_for_extension(extension: &str) -> Option<&'static str> {
125 let ext = extension.to_ascii_lowercase();
127 Some(match ext.as_str() {
128 "bash" | "sh" | "zsh" | "ksh" | "bashrc" | "zshrc" => "bash",
129 "css" => "css",
130 "dockerfile" => "dockerfile",
131 "go" => "go",
132 "java" => "java",
133 "js" | "mjs" | "cjs" | "jsx" => "javascript",
134 "json" | "jsonc" | "json5" | "webmanifest" => "json",
135 "md" | "markdown" | "mdown" | "mkd" | "mkdn" => "markdown",
136 "nix" => "nix",
137 "py" | "pyi" | "pyw" => "python",
138 "rb" | "rake" | "gemspec" => "ruby",
139 "rs" => "rust",
140 "scala" | "sbt" | "sc" => "scala",
141 "sql" => "sql",
142 "ts" | "tsx" | "mts" | "cts" => "typescript",
143 "xml" | "html" | "htm" | "xhtml" | "svg" | "plist" | "xsl" | "xslt" => "xml",
144 "yaml" | "yml" => "yaml",
145 _ => return None,
146 })
147}
148
149pub const HLJS_LANGUAGES: &[&str] = &[
151 "bash",
152 "css",
153 "dockerfile",
154 "go",
155 "java",
156 "javascript",
157 "json",
158 "markdown",
159 "nix",
160 "python",
161 "ruby",
162 "rust",
163 "scala",
164 "sql",
165 "typescript",
166 "xml",
167 "yaml",
168];
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_hljs_files_not_empty() {
176 for (path, content, _mime) in HLJS_FILES.iter() {
177 assert!(
178 !content.is_empty(),
179 "HLJS file {} should not be empty",
180 path
181 );
182 }
183 }
184
185 #[test]
186 fn test_hljs_file_count() {
187 assert_eq!(HLJS_FILES.len(), 19);
189 }
190
191 #[test]
192 fn test_all_languages_have_files() {
193 for lang in HLJS_LANGUAGES {
194 let expected_path = format!("/hljs.lang.{}.js", lang);
195 assert!(
196 HLJS_FILES.iter().any(|(path, _, _)| *path == expected_path),
197 "Missing HLJS file for language: {}",
198 lang
199 );
200 }
201 }
202
203 #[test]
204 fn test_core_files_present() {
205 assert!(
206 HLJS_FILES.iter().any(|(path, _, _)| *path == "/hljs.js"),
207 "Core hljs.js should be present"
208 );
209 assert!(
210 HLJS_FILES
211 .iter()
212 .any(|(path, _, _)| *path == "/hljs.atom-one-dark.css"),
213 "Dark theme CSS should be present"
214 );
215 }
216
217 #[test]
218 fn test_every_mapped_language_is_embedded() {
219 let mapped = [
222 "sh",
223 "css",
224 "dockerfile",
225 "go",
226 "java",
227 "jsx",
228 "json",
229 "md",
230 "nix",
231 "py",
232 "rb",
233 "rs",
234 "scala",
235 "sql",
236 "tsx",
237 "svg",
238 "yml",
239 ];
240 for ext in mapped {
241 let lang = language_for_extension(ext)
242 .unwrap_or_else(|| panic!("extension {ext} should map to a language"));
243 assert!(
244 HLJS_LANGUAGES.contains(&lang),
245 "{ext} maps to {lang}, which has no embedded hljs module"
246 );
247 }
248 }
249
250 #[test]
251 fn test_language_for_extension_is_case_insensitive() {
252 assert_eq!(language_for_extension("RS"), Some("rust"));
253 assert_eq!(language_for_extension("Json"), Some("json"));
254 }
255
256 #[test]
257 fn test_language_for_extension_unknown_is_none() {
258 for ext in ["txt", "log", "toml", "csv", "", "exe"] {
261 assert_eq!(language_for_extension(ext), None, "unexpected match: {ext}");
262 }
263 }
264
265 #[test]
266 fn test_mime_types_correct() {
267 for (path, _, mime) in HLJS_FILES.iter() {
268 if path.ends_with(".css") {
269 assert_eq!(
270 *mime, "text/css",
271 "CSS files should have text/css mime type"
272 );
273 } else if path.ends_with(".js") {
274 assert_eq!(
275 *mime, "application/javascript",
276 "JS files should have application/javascript mime type"
277 );
278 }
279 }
280 }
281}