use std::path::{Path, PathBuf};
use super::yaml::render_yaml_template;
use crate::{
config::{ConfigResult, ConfigSchema},
config_format::{ConfigFormat, json5_options, toml_options, yaml_options},
};
pub fn template_for_path<S>(path: impl AsRef<Path>) -> ConfigResult<String>
where
S: ConfigSchema,
{
let template = match ConfigFormat::from_path(path.as_ref()) {
ConfigFormat::Yaml => confique::yaml::template::<S>(yaml_options()),
ConfigFormat::Toml => confique::toml::template::<S>(toml_options()),
ConfigFormat::Json => confique::json5::template::<S>(json5_options()),
};
Ok(template)
}
pub(super) fn template_for_target<S>(
path: &Path,
include_paths: &[PathBuf],
section_path: &[&'static str],
split_paths: &[Vec<&'static str>],
env_only_paths: &[Vec<&'static str>],
) -> ConfigResult<String>
where
S: ConfigSchema,
{
if ConfigFormat::from_path(path) != ConfigFormat::Yaml
|| (split_paths.is_empty() && env_only_paths.is_empty())
{
return template_for_path_with_includes::<S>(path, include_paths);
}
Ok(render_yaml_template(
&S::META,
include_paths,
section_path,
split_paths,
env_only_paths,
))
}
fn template_for_path_with_includes<S>(
path: &Path,
include_paths: &[PathBuf],
) -> ConfigResult<String>
where
S: ConfigSchema,
{
let template = template_for_path::<S>(path)?;
if include_paths.is_empty() {
return Ok(template);
}
let template = match ConfigFormat::from_path(path) {
ConfigFormat::Yaml => {
let template = strip_prefix_once(&template, "# Default value: []\n#include: []\n\n");
format!("{}\n{template}", render_yaml_include(include_paths))
}
ConfigFormat::Toml => {
let template = strip_prefix_once(&template, "# Default value: []\n#include = []\n\n");
format!("{}\n{template}", render_toml_include(include_paths))
}
ConfigFormat::Json => {
let body = template.strip_prefix("{\n").unwrap_or(&template);
let body = strip_prefix_once(body, " // Default value: []\n //include: [],\n\n");
format!("{{\n{}\n{body}", render_json5_include(include_paths))
}
};
Ok(template)
}
pub(super) fn render_yaml_include(paths: &[PathBuf]) -> String {
let mut out = String::from("include:\n");
for path in paths {
out.push_str(" - ");
out.push_str("e_path(path));
out.push('\n');
}
out
}
fn render_toml_include(paths: &[PathBuf]) -> String {
let entries = paths
.iter()
.map(|path| quote_path(path))
.collect::<Vec<_>>()
.join(", ");
format!("include = [{entries}]\n")
}
fn render_json5_include(paths: &[PathBuf]) -> String {
let mut out = String::from(" include: [\n");
for path in paths {
out.push_str(" ");
out.push_str("e_path(path));
out.push_str(",\n");
}
out.push_str(" ],\n");
out
}
pub(super) fn quote_path(path: &Path) -> String {
serde_json::to_string(&path.to_string_lossy()).expect("path string serialization cannot fail")
}
fn strip_prefix_once<'a>(value: &'a str, prefix: &str) -> &'a str {
value.strip_prefix(prefix).unwrap_or(value)
}