use std::path::{Path, PathBuf};
use serde_json::Value;
use crate::error::EngineResult;
use crate::flatten;
use crate::load_budget::read_to_end_capped;
use crate::output_pipeline::{PolicyInputOptions, ReferenceMode};
use crate::schema_override;
#[derive(Debug, Default)]
pub struct PolicyInputs {
prepared_override_schemas: Vec<Value>,
}
impl PolicyInputs {
pub(super) fn override_count(&self) -> usize {
self.prepared_override_schemas.len()
}
pub(super) fn into_prepared_override_schemas(self) -> Vec<Value> {
self.prepared_override_schemas
}
}
#[tracing::instrument(skip_all, fields(override_count = paths.len()))]
pub fn load_policy_inputs(
paths: &[PathBuf],
options: &PolicyInputOptions,
) -> EngineResult<PolicyInputs> {
let prepared_override_schemas = paths
.iter()
.map(|path| load_prepared_override_schema(path, options))
.collect::<EngineResult<Vec<_>>>()?;
Ok(PolicyInputs {
prepared_override_schemas,
})
}
#[tracing::instrument(skip_all)]
fn load_prepared_override_schema(path: &Path, options: &PolicyInputOptions) -> EngineResult<Value> {
let mut override_schema = load_json_file(path, options.load_budget.max_schema_document_bytes)?;
schema_override::mark_refs_for_replacement(&mut override_schema);
prepare_override_schema(override_schema, path, options)
}
#[tracing::instrument(skip_all, fields(reference_mode = ?options.reference_mode))]
fn prepare_override_schema(
schema: Value,
override_path: &Path,
options: &PolicyInputOptions,
) -> EngineResult<Value> {
let override_base = override_path.parent().unwrap_or_else(|| Path::new("."));
match options.reference_mode {
ReferenceMode::SelfContained => flatten::bundle_refs(
schema,
override_base,
options.fetch_policy,
options.load_budget,
),
ReferenceMode::FullyInlinedExport => flatten::flatten_refs(
&schema,
override_base,
options.fetch_policy,
options.load_budget,
),
ReferenceMode::PreserveRefs => Ok(schema),
}
}
fn load_json_file(path: &Path, max_bytes: usize) -> EngineResult<Value> {
let mut file = std::fs::File::open(path)?;
let bytes = read_to_end_capped(&mut file, max_bytes, path.display().to_string())?;
let value: Value = serde_json::from_slice(&bytes)?;
Ok(value)
}
#[cfg(test)]
#[path = "tests/overrides.rs"]
mod tests;