From f11db9859684b33407a6d979997e8cb48c0ca285 Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin Date: Sat, 15 Jun 2024 07:58:11 +0800 Subject: [PATCH] feat: generate description metadata for SEO --- Cargo.lock | 10 ++++++++++ Cargo.toml | 2 ++ cli/Cargo.toml | 1 + cli/src/project.rs | 29 ++++++++++++++++++++++++----- cli/src/render/typst.rs | 23 +++++++++++++++++++---- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 096b6a4..f381d43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2933,6 +2933,7 @@ dependencies = [ "typst-ts-compiler", "typst-ts-core", "typst-ts-svg-exporter", + "typst-ts-text-exporter", "vergen", "warp", ] @@ -3749,6 +3750,15 @@ dependencies = [ "typst-ts-core", ] +[[package]] +name = "typst-ts-text-exporter" +version = "0.5.0-rc4" +source = "git+https://github.com/Myriad-Dreamin/typst.ts?rev=6cc978011c16328b7aaa0dc660bb73818977475b#6cc978011c16328b7aaa0dc660bb73818977475b" +dependencies = [ + "typst", + "typst-ts-core", +] + [[package]] name = "ucd-trie" version = "0.1.6" diff --git a/Cargo.toml b/Cargo.toml index 9e84279..1d9eb6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ typst = "0.11.1" typst-assets = "0.11.1" typst-ts-core = { version = "0.5.0-rc4" } typst-ts-compiler = { version = "0.5.0-rc4" } +typst-ts-text-exporter = { version = "0.5.0-rc4" } typst-ts-svg-exporter = { version = "0.5.0-rc4", features = [ "experimental-ligature", ] } @@ -70,6 +71,7 @@ pathdiff = "0.2.1" typst = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "typst.ts-v0.11.1-content-hint" } typst-syntax = { git = "https://github.com/Myriad-Dreamin/typst.git", branch = "typst.ts-v0.11.1-content-hint" } typst-ts-svg-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "6cc978011c16328b7aaa0dc660bb73818977475b", package = "typst-ts-svg-exporter" } +typst-ts-text-exporter = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "6cc978011c16328b7aaa0dc660bb73818977475b", package = "typst-ts-text-exporter" } typst-ts-core = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "6cc978011c16328b7aaa0dc660bb73818977475b", package = "typst-ts-core" } typst-ts-compiler = { git = "https://github.com/Myriad-Dreamin/typst.ts", rev = "6cc978011c16328b7aaa0dc660bb73818977475b", package = "typst-ts-compiler" } diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 313a836..c996baf 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -51,6 +51,7 @@ typst-ts-compiler.workspace = true handlebars.workspace = true typst-ts-svg-exporter.workspace = true +typst-ts-text-exporter.workspace = true pathdiff.workspace = true [build-dependencies] diff --git a/cli/src/project.rs b/cli/src/project.rs index 596be4a..45185a4 100644 --- a/cli/src/project.rs +++ b/cli/src/project.rs @@ -5,6 +5,7 @@ use log::warn; use serde::{Deserialize, Serialize}; use serde_json::json; use typst_ts_compiler::service::Compiler; +use typst_ts_core::escape::{escape_str, AttributeEscapes}; use crate::{ error::prelude::*, @@ -341,7 +342,7 @@ impl Project { chapters } - pub fn compile_chapter(&mut self, _ch: DataDict, path: &str) -> ZResult { + pub fn compile_chapter(&mut self, _ch: DataDict, path: &str) -> ZResult { let rel_data_path = std::path::Path::new(&self.path_to_root) .join(path) .with_extension("") @@ -350,7 +351,7 @@ impl Project { // windows .replace('\\', "/"); - self.tr.compile_page(Path::new(path))?; + let doc = self.tr.compile_page(Path::new(path))?; let dynamic_load_trampoline = self .hr @@ -365,7 +366,15 @@ impl Project { "render typst_load_trampoline for compile_chapter", ))?; - Ok(dynamic_load_trampoline.to_owned()) + let description = self.tr.generate_desc(&doc)?; + + Ok(ChapterArtifact { + content: dynamic_load_trampoline.to_owned(), + description: escape_str::( + &description.chars().take(512).collect::(), + ) + .into_owned(), + }) } pub fn render_chapter(&mut self, chapter_data: DataDict, path: &str) -> ZResult { @@ -383,11 +392,16 @@ impl Project { let renderer_module = format!("{}internal/typst_ts_renderer_bg.wasm", self.path_to_root); data.insert("renderer_module".to_owned(), json!(renderer_module)); + // inject content + + let art = self.compile_chapter(chapter_data, path)?; + // inject content data.insert( - "content".to_owned(), - serde_json::Value::String(self.compile_chapter(chapter_data, path)?), + "description".to_owned(), + serde_json::Value::String(art.description), ); + data.insert("content".to_owned(), serde_json::Value::String(art.content)); // inject path_to_root data.insert("path_to_root".to_owned(), json!(self.path_to_root)); @@ -423,3 +437,8 @@ impl Project { // } // } } + +pub struct ChapterArtifact { + pub description: String, + pub content: String, +} diff --git a/cli/src/render/typst.rs b/cli/src/render/typst.rs index 0fa3d91..e2b49aa 100644 --- a/cli/src/render/typst.rs +++ b/cli/src/render/typst.rs @@ -21,7 +21,7 @@ use typst_ts_core::{ config::{compiler::EntryOpts, CompileOpts}, path::PathClean, vector::ir::{LayoutRegionNode, PageMetadata}, - TakeAs, TypstAbs, TypstDocument, + TakeAs, Transformer, TypstAbs, TypstDocument, }; const THEME_LIST: [&str; 5] = ["light", "rust", "coal", "navy", "ayu"]; @@ -136,9 +136,11 @@ impl TypstRenderer { .ok_or_else(|| error_once!("compile book.typ")) } - pub fn compile_page(&mut self, path: &Path) -> ZResult<()> { + pub fn compile_page(&mut self, path: &Path) -> ZResult> { self.setup_entry(path); + let mut any_doc = None; + for theme in THEME_LIST { self.set_theme_target(theme); @@ -189,10 +191,23 @@ impl TypstRenderer { }); let res = self.compiler.compile(&mut self.fork_env::()); - self.report(res) + let doc = self + .report(res) .ok_or_else(|| error_once!("compile page theme", theme: theme))?; + any_doc = Some(doc.clone()); } - Ok(()) + any_doc.ok_or_else(|| error_once!("compile page.typ")) + } + + pub fn generate_desc(&mut self, doc: &TypstDocument) -> ZResult { + let e = typst_ts_text_exporter::TextExporter::default(); + let mut w = std::io::Cursor::new(Vec::new()); + e.export(self.compiler.world(), (Arc::new(doc.clone()), &mut w)) + .map_err(|e| error_once!("export text", error: format!("{e:?}")))?; + + let w = w.into_inner(); + + String::from_utf8(w).map_err(|e| error_once!("export text", error: format!("{e:?}"))) } }