tighterror-build 0.0.22

The tighterror code generation library.
Documentation
use crate::{
    coder::CodegenOptions,
    errors::{kind::coder::OUTPUT_PATH_NOT_DIRECTORY, TbError},
    spec::{definitions::*, Spec},
};
use std::path::PathBuf;

#[derive(Debug)]
pub struct FrozenOptions {
    pub(crate) output: PathBuf,
    pub(crate) test: bool,
    pub(crate) update: bool,
    pub(crate) separate_files: bool,
}

impl FrozenOptions {
    pub fn new(opts: &CodegenOptions, spec: &Spec) -> Result<Self, TbError> {
        let op = Self::output_path(opts, spec)?;
        Ok(Self {
            output: op.path,
            test: opts.test.unwrap_or(DEFAULT_TEST),
            update: opts.update.unwrap_or(DEFAULT_UPDATE_MODE),
            separate_files: op.separate_files,
        })
    }

    fn output_path(opts: &CodegenOptions, spec: &Spec) -> Result<OutputPath, TbError> {
        let output = spec.main.output(&spec.path, opts.output.as_deref())?;
        if output.as_os_str() == STDOUT_PATH {
            return Ok(OutputPath {
                path: output,
                separate_files: false,
            });
        }

        let separate_files = opts.separate_files.unwrap_or(DEFAULT_SEPARATE_FILES);
        let is_dir = output.is_dir();

        if separate_files && !is_dir {
            log::error!("output path must be a directory in separate-files mode: {output:?}");
            return OUTPUT_PATH_NOT_DIRECTORY.into();
        }

        let op = if is_dir && !separate_files {
            output.join(IMPLICIT_FILENAME)
        } else {
            output
        };

        Ok(OutputPath {
            path: op,
            separate_files,
        })
    }
}

#[derive(Debug)]
struct OutputPath {
    path: PathBuf,
    separate_files: bool,
}