Skip to content

Commit

Permalink
Only load used language highlight module in code preview (ordinals#2696)
Browse files Browse the repository at this point in the history
  • Loading branch information
casey authored Nov 19, 2023
1 parent ef41aa7 commit 6630c51
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 69 deletions.
108 changes: 72 additions & 36 deletions src/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use {
#[derive(Debug, PartialEq, Copy, Clone)]
pub(crate) enum Media {
Audio,
Code,
Code(Language),
Font,
Iframe,
Image,
Expand All @@ -22,44 +22,70 @@ pub(crate) enum Media {
Video,
}

#[derive(Debug, PartialEq, Copy, Clone)]
pub(crate) enum Language {
Css,
JavaScript,
Json,
Python,
Yaml,
}

impl Display for Language {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
Self::Css => "css",
Self::JavaScript => "javascript",
Self::Json => "json",
Self::Python => "python",
Self::Yaml => "yaml",
}
)
}
}

impl Media {
#[rustfmt::skip]
const TABLE: &'static [(&'static str, BrotliEncoderMode, Media, &'static [&'static str])] = &[
("application/cbor", BROTLI_MODE_GENERIC, Media::Unknown, &["cbor"]),
("application/json", BROTLI_MODE_TEXT, Media::Code, &["json"]),
("application/pdf", BROTLI_MODE_GENERIC, Media::Pdf, &["pdf"]),
("application/pgp-signature", BROTLI_MODE_TEXT, Media::Text, &["asc"]),
("application/protobuf", BROTLI_MODE_GENERIC, Media::Unknown, &["binpb"]),
("application/octet-stream", BROTLI_MODE_GENERIC, Media::Unknown, &["bin"]),
("application/yaml", BROTLI_MODE_TEXT, Media::Code, &["yaml", "yml"]),
("audio/flac", BROTLI_MODE_GENERIC, Media::Audio, &["flac"]),
("audio/mpeg", BROTLI_MODE_GENERIC, Media::Audio, &["mp3"]),
("audio/wav", BROTLI_MODE_GENERIC, Media::Audio, &["wav"]),
("font/otf", BROTLI_MODE_GENERIC, Media::Font, &["otf"]),
("font/ttf", BROTLI_MODE_GENERIC, Media::Font, &["ttf"]),
("font/woff", BROTLI_MODE_GENERIC, Media::Font, &["woff"]),
("font/woff2", BROTLI_MODE_FONT, Media::Font, &["woff2"]),
("image/apng", BROTLI_MODE_GENERIC, Media::Image, &["apng"]),
("image/avif", BROTLI_MODE_GENERIC, Media::Image, &[]),
("image/gif", BROTLI_MODE_GENERIC, Media::Image, &["gif"]),
("image/jpeg", BROTLI_MODE_GENERIC, Media::Image, &["jpg", "jpeg"]),
("image/png", BROTLI_MODE_GENERIC, Media::Image, &["png"]),
("image/svg+xml", BROTLI_MODE_TEXT, Media::Iframe, &["svg"]),
("image/webp", BROTLI_MODE_GENERIC, Media::Image, &["webp"]),
("model/gltf+json", BROTLI_MODE_TEXT, Media::Model, &["gltf"]),
("model/gltf-binary", BROTLI_MODE_GENERIC, Media::Model, &["glb"]),
("model/stl", BROTLI_MODE_GENERIC, Media::Unknown, &["stl"]),
("text/css", BROTLI_MODE_TEXT, Media::Code, &["css"]),
("text/html", BROTLI_MODE_TEXT, Media::Iframe, &[]),
("text/html;charset=utf-8", BROTLI_MODE_TEXT, Media::Iframe, &["html"]),
("text/javascript", BROTLI_MODE_TEXT, Media::Code, &["js"]),
("text/markdown", BROTLI_MODE_TEXT, Media::Markdown, &[]),
("text/markdown;charset=utf-8", BROTLI_MODE_TEXT, Media::Markdown, &["md"]),
("text/plain", BROTLI_MODE_TEXT, Media::Text, &[]),
("text/plain;charset=utf-8", BROTLI_MODE_TEXT, Media::Text, &["txt"]),
("text/x-python", BROTLI_MODE_TEXT, Media::Code, &["py"]),
("video/mp4", BROTLI_MODE_GENERIC, Media::Video, &["mp4"]),
("video/webm", BROTLI_MODE_GENERIC, Media::Video, &["webm"]),
("application/cbor", BROTLI_MODE_GENERIC, Media::Unknown, &["cbor"]),
("application/json", BROTLI_MODE_TEXT, Media::Code(Language::Json), &["json"]),
("application/octet-stream", BROTLI_MODE_GENERIC, Media::Unknown, &["bin"]),
("application/pdf", BROTLI_MODE_GENERIC, Media::Pdf, &["pdf"]),
("application/pgp-signature", BROTLI_MODE_TEXT, Media::Text, &["asc"]),
("application/protobuf", BROTLI_MODE_GENERIC, Media::Unknown, &["binpb"]),
("application/x-javascript", BROTLI_MODE_TEXT, Media::Code(Language::JavaScript), &[]),
("application/yaml", BROTLI_MODE_TEXT, Media::Code(Language::Yaml), &["yaml", "yml"]),
("audio/flac", BROTLI_MODE_GENERIC, Media::Audio, &["flac"]),
("audio/mpeg", BROTLI_MODE_GENERIC, Media::Audio, &["mp3"]),
("audio/wav", BROTLI_MODE_GENERIC, Media::Audio, &["wav"]),
("font/otf", BROTLI_MODE_GENERIC, Media::Font, &["otf"]),
("font/ttf", BROTLI_MODE_GENERIC, Media::Font, &["ttf"]),
("font/woff", BROTLI_MODE_GENERIC, Media::Font, &["woff"]),
("font/woff2", BROTLI_MODE_FONT, Media::Font, &["woff2"]),
("image/apng", BROTLI_MODE_GENERIC, Media::Image, &["apng"]),
("image/avif", BROTLI_MODE_GENERIC, Media::Image, &[]),
("image/gif", BROTLI_MODE_GENERIC, Media::Image, &["gif"]),
("image/jpeg", BROTLI_MODE_GENERIC, Media::Image, &["jpg", "jpeg"]),
("image/png", BROTLI_MODE_GENERIC, Media::Image, &["png"]),
("image/svg+xml", BROTLI_MODE_TEXT, Media::Iframe, &["svg"]),
("image/webp", BROTLI_MODE_GENERIC, Media::Image, &["webp"]),
("model/gltf+json", BROTLI_MODE_TEXT, Media::Model, &["gltf"]),
("model/gltf-binary", BROTLI_MODE_GENERIC, Media::Model, &["glb"]),
("model/stl", BROTLI_MODE_GENERIC, Media::Unknown, &["stl"]),
("text/css", BROTLI_MODE_TEXT, Media::Code(Language::Css), &["css"]),
("text/html", BROTLI_MODE_TEXT, Media::Iframe, &[]),
("text/html;charset=utf-8", BROTLI_MODE_TEXT, Media::Iframe, &["html"]),
("text/javascript", BROTLI_MODE_TEXT, Media::Code(Language::JavaScript), &["js"]),
("text/markdown", BROTLI_MODE_TEXT, Media::Markdown, &[]),
("text/markdown;charset=utf-8", BROTLI_MODE_TEXT, Media::Markdown, &["md"]),
("text/plain", BROTLI_MODE_TEXT, Media::Text, &[]),
("text/plain;charset=utf-8", BROTLI_MODE_TEXT, Media::Text, &["txt"]),
("text/x-python", BROTLI_MODE_TEXT, Media::Code(Language::Python), &["py"]),
("video/mp4", BROTLI_MODE_GENERIC, Media::Video, &["mp4"]),
("video/webm", BROTLI_MODE_GENERIC, Media::Video, &["webm"]),
];

pub(crate) fn content_type_for_path(
Expand Down Expand Up @@ -172,4 +198,14 @@ mod tests {
fn av1_in_mp4_is_rejected() {
assert!(Media::check_mp4_codec(Path::new("examples/av1.mp4")).is_err(),);
}

#[test]
fn no_duplicate_exensions() {
let mut set = HashSet::new();
for (_, _, _, extensions) in Media::TABLE {
for extension in *extensions {
assert!(set.insert(extension), "duplicate extension `{extension}`");
}
}
}
}
27 changes: 13 additions & 14 deletions src/subcommand/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1066,24 +1066,28 @@ impl Server {

match inscription.media() {
Media::Audio => Ok(PreviewAudioHtml { inscription_id }.into_response()),
Media::Code => Ok(
Media::Code(language) => Ok(
(
[(
header::CONTENT_SECURITY_POLICY,
"script-src-elem 'self' https://cdn.jsdelivr.net; href-src 'self' https://cdn.jsdelivr.net",
"script-src-elem 'self' https://cdn.jsdelivr.net",
)],
PreviewCodeHtml { inscription_id },
PreviewCodeHtml {
inscription_id,
language,
},
)
.into_response(),
),
Media::Font => Ok(
(
[(
header::CONTENT_SECURITY_POLICY,
"script-src-elem 'self'; style-src 'self' 'unsafe-inline';",
header::CONTENT_SECURITY_POLICY,
"script-src-elem 'self'; style-src 'self' 'unsafe-inline';",
)],
PreviewFontHtml { inscription_id }
).into_response(),
PreviewFontHtml { inscription_id },
)
.into_response(),
),
Media::Iframe => Ok(
Self::content_response(inscription, accept_encoding)?
Expand Down Expand Up @@ -1130,12 +1134,7 @@ impl Server {
)
.into_response(),
),
Media::Text => {
Ok(
PreviewTextHtml { inscription_id }
.into_response(),
)
}
Media::Text => Ok(PreviewTextHtml { inscription_id }.into_response()),
Media::Unknown => Ok(PreviewUnknownHtml.into_response()),
Media::Video => Ok(PreviewVideoHtml { inscription_id }.into_response()),
}
Expand Down Expand Up @@ -3161,7 +3160,7 @@ mod tests {
server.assert_response_regex(
format!("/preview/{inscription_id}"),
StatusCode::OK,
format!(r".*<html lang=en data-inscription={inscription_id}>.*"),
format!(r".*<html lang=en data-inscription={inscription_id} data-language=javascript>.*"),
);
}

Expand Down
1 change: 1 addition & 0 deletions src/templates/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub(crate) struct PreviewAudioHtml {
#[derive(boilerplate::Boilerplate)]
pub(crate) struct PreviewCodeHtml {
pub(crate) inscription_id: InscriptionId,
pub(crate) language: media::Language,
}

#[derive(boilerplate::Boilerplate)]
Expand Down
28 changes: 10 additions & 18 deletions static/preview-code.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
import hljs from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/highlight.min.js';
import css from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/css.min.js';
import javascript from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/javascript.min.js';
import json from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/json.min.js';
import python from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/python.min.js';
import yaml from 'https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/yaml.min.js';

hljs.registerLanguage('css', css);
hljs.registerLanguage('javascript', javascript);
hljs.registerLanguage('json', json);
hljs.registerLanguage('python', python);
hljs.registerLanguage('yaml', yaml);

const inscription = document.documentElement.dataset.inscription;
const language = document.documentElement.dataset.language;

const definition = await import(`https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/es/languages/${language}.min.js`);

hljs.registerLanguage(language, definition.default);

const response = await fetch(`/content/${inscription}`);
const contentType = response.headers.get("content-type");
let language = contentType.split("/")[1];
if (language === "x-python") {
language = "python";
}
const code = await response.text();
document.body.innerHTML = `<pre><code>${hljs.highlight(code, {language, ignoreIllegals: true}).value}</code></pre>`;
const text = await response.text();
const code = document.querySelector('code');

code.innerHTML = hljs.highlight(text, {language, ignoreIllegals: true}).value;
3 changes: 2 additions & 1 deletion templates/preview-code.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<!doctype html>
<html lang=en data-inscription={{self.inscription_id}}>
<html lang=en data-inscription={{self.inscription_id}} data-language={{self.language}}>
<head>
<meta charset=utf-8>
<link rel=stylesheet href=/static/preview-code.css>
<script src=/static/preview-code.js defer type=module></script>
</head>
<body>
<pre><code></code></pre>
</body>
</html>

0 comments on commit 6630c51

Please sign in to comment.