use crate::prelude::*;
pub fn resolve_id_by_path(
world: &dyn World,
current: TypstFileId,
import_path: &str,
) -> Option<TypstFileId> {
if import_path.starts_with('@') {
let spec = import_path.parse::<PackageSpec>().ok()?;
let manifest_id = TypstFileId::new(RootedPath::new(
VirtualRoot::Package(spec.clone()),
VirtualPath::new("typst.toml").ok()?,
));
let bytes = world.file(manifest_id).ok()?;
let string = std::str::from_utf8(&bytes).map_err(FileError::from).ok()?;
let manifest: PackageManifest = toml::from_str(string).ok()?;
manifest.validate(&spec).ok()?;
return Some(
resolve_path_from_id(manifest_id, manifest.package.entrypoint.as_str())
.ok()?
.intern(),
);
}
Some(resolve_path_from_id(current, import_path).ok()?.intern())
}
pub fn find_source_by_expr(
world: &dyn World,
current: TypstFileId,
import_source: ast::Expr,
) -> Option<Source> {
match import_source {
ast::Expr::Str(s) => world
.source(resolve_id_by_path(world, current, s.get().as_str())?)
.ok(),
_ => None,
}
}
pub fn cast_include_expr<'a>(name: &str, node: ast::Expr<'a>) -> Option<ast::Expr<'a>> {
match node {
ast::Expr::ModuleInclude(inc) => Some(inc.source()),
ast::Expr::CodeBlock(code) => {
let exprs = code.body();
if exprs.exprs().count() != 1 {
eprintln!("example function must have a single inclusion: {name}");
return None;
}
cast_include_expr(name, exprs.exprs().next().unwrap())
}
_ => {
eprintln!("example function must have a single inclusion: {name}");
None
}
}
}