1use crate::error::{ErrorCode, MdzError, Result};
4use crate::manifest::{Manifest, entry_point_value_problem};
5use crate::paths::{find_path, is_markdown, is_support_file, strip_dot_slash};
6
7pub fn resolve_entry_point<'a, I>(paths: I, manifest: Option<&Manifest>) -> Result<String>
22where
23 I: IntoIterator<Item = &'a str>,
24{
25 let files: Vec<&str> = paths.into_iter().filter(|p| !p.ends_with('/')).collect();
26
27 if let Some(value) = manifest.and_then(|m| m.get("entryPoint")) {
28 if let Some(problem) = entry_point_value_problem(value) {
29 return Err(MdzError::new(ErrorCode::EntryPointInvalid, problem));
30 }
31 let wanted = value.as_str().unwrap_or_default();
32 return find_path(files.iter().copied(), strip_dot_slash(wanted))
33 .map(str::to_owned)
34 .ok_or_else(|| {
35 MdzError::new(
36 ErrorCode::EntryPointMissing,
37 format!("entryPoint '{wanted}' is not in the archive"),
38 )
39 });
40 }
41
42 if let Some(index) = find_path(files.iter().copied(), "index.md") {
43 return Ok(index.to_owned());
44 }
45
46 let root_markdown: Vec<&str> = files
47 .iter()
48 .copied()
49 .filter(|p| !p.contains('/') && is_markdown(p))
50 .collect();
51 let content: Vec<&str> = root_markdown.iter().copied().filter(|p| !is_support_file(p)).collect();
52 if content.len() == 1 {
53 return Ok(content[0].to_owned());
54 }
55 if content.is_empty() && root_markdown.len() == 1 {
56 return Ok(root_markdown[0].to_owned());
57 }
58 if root_markdown.is_empty() {
59 return Err(MdzError::new(
60 ErrorCode::EntryPointUnresolved,
61 "no Markdown file at the archive root",
62 ));
63 }
64 let mut names = root_markdown;
65 names.sort_unstable();
66 Err(MdzError::new(
67 ErrorCode::EntryPointUnresolved,
68 format!(
69 "several root Markdown files and no index.md or manifest entryPoint: {}",
70 names.join(", ")
71 ),
72 ))
73}