Repository: typst/typst
File: crates/typst-cli/src/compile.rs (Rust)

Code before:
                Some(ext) if ext.eq_ignore_ascii_case("svg") => OutputFormat::Svg,
                _ => bail!(
                    "could not infer output format for path {}.\n\
                     consider providing the format manually with `--format/-f`",
                    output.display()
                ),
            }
        } else {
            OutputFormat::Pdf
        })
    }

    /// The ranges of the pages to be exported as specified by the user.
    ///
    /// This returns `None` if all pages should be exported.
    pub fn exported_page_ranges(&self) -> Option<PageRanges> {
        self.pages.as_ref().map(|export_ranges| {
            PageRanges::new(
                export_ranges.iter().map(PageRangeArgument::to_range).collect(),
            )
        })
    }

    /// The PDF standards to try to conform with.
    pub fn pdf_standards(&self) -> StrResult<PdfStandards> {
        if self.pdf_standard.contains(&PdfStandard::A_2b)
            && self.pdf_standard.contains(&PdfStandard::A_3b)
        {
            bail!("PDF can not conform to A-2B and A-3B at the same time")
        }

        let list = self
            .pdf_standard
            .iter()
            .map(|standard| match standard {
                PdfStandard::V_1_7 => typst_pdf::PdfStandard::V_1_7,
                PdfStandard::A_2b => typst_pdf::PdfStandard::A_2b,
                PdfStandard::A_3b => typst_pdf::PdfStandard::A_3b,
            })
            .collect::<Vec<_>>();
        PdfStandards::new(&list)
    }
}

/// Execute a compilation command.
pub fn compile(mut timer: Timer, mut command: CompileCommand) -> StrResult<()> {
    // Only meant for input validation
    _ = command.output_format()?;

    let mut world =
        SystemWorld::new(&command.common).map_err(|err| eco_format!("{err}"))?;

Review comment (suggestion):
This check should be moved to `typst_pdf::PdfStandards::new` as it is not CLI specific.

Code after:
    /// The format to emit diagnostics in.
    pub diagnostic_format: DiagnosticFormat,
    /// Opens the output file with the default viewer or a specific program after
    /// compilation.
    pub open: Option<Option<String>>,
    /// One (or multiple comma-separated) PDF standards that Typst will enforce
    /// conformance with.
    pub pdf_standards: PdfStandards,
    /// A path to write a Makefile rule describing the current compilation.
    pub make_deps: Option<PathBuf>,
    /// The PPI (pixels per inch) to use for PNG export.
    pub ppi: f32,
    /// The export cache for images, used for caching output files in `typst
    /// watch` sessions with images.
    pub export_cache: ExportCache,
    /// Server for `typst watch` to HTML.
    #[cfg(feature = "http-server")]
    pub server: Option<HtmlServer>,
}

impl CompileConfig {
    /// Preprocess a `CompileCommand`, producing a compilation config.
    pub fn new(command: &CompileCommand) -> StrResult<Self> {
        Self::new_impl(&command.args, None)
    }

    /// Preprocess a `WatchCommand`, producing a compilation config.
    pub fn watching(command: &WatchCommand) -> StrResult<Self> {
        Self::new_impl(&command.args, Some(command))
    }

    /// The shared implementation of [`CompileConfig::new`] and
    /// [`CompileConfig::watching`].
    fn new_impl(args: &CompileArgs, watch: Option<&WatchCommand>) -> StrResult<Self> {
        let input = args.input.clone();

        let output_format = if let Some(specified) = args.format {
            specified
        } else if let Some(Output::Path(output)) = &args.output {
            match output.extension() {
                Some(ext) if ext.eq_ignore_ascii_case("pdf") => OutputFormat::Pdf,
                Some(ext) if ext.eq_ignore_ascii_case("png") => OutputFormat::Png,
                Some(ext) if ext.eq_ignore_ascii_case("svg") => OutputFormat::Svg,
                Some(ext) if ext.eq_ignore_ascii_case("html") => OutputFormat::Html,
                _ => bail!(
                    "could not infer output format for path {}.\n\
                     consider providing the format manually with `--format/-f`",
                    output.display()
                ),
            }
        } else {