use crate::core::backend::GeneratedFile;
use crate::core::config::{Language, ResolvedCrateConfig};
use std::path::PathBuf;
const EXCLUDES: &[&str] = &[
"**/*.freezed.dart",
"**/*.g.dart",
"**/*.jinja",
"**/*.lock",
"**/Cargo.lock",
"**/go.sum",
"**/package-lock.json",
"**/pnpm-lock.yaml",
"**/uv.lock",
".alef/**",
"artifacts/**",
"dist/**",
"docs/assets/**",
"docs/snippets/**",
"fixtures/**",
"node_modules/**",
"readme_templates/**",
"target/**",
"templates/readme/**",
"test_documents/**",
"vendor/**",
];
const RUFF_IGNORE: &[&str] = &[
"ANN401", "ASYNC109", "ASYNC110", "BLE001", "COM812", "D100", "D104", "D107", "D205", "E501", "EM", "FBT", "FIX",
"ISC001", "PD011", "PGH003", "PLR2004", "PLW0603", "S104", "S110", "S603", "TD", "TRY",
];
const RUMDL_DISABLE: &[&str] = &[
"MD012", "MD013", "MD024", "MD033", "MD036", "MD041", "MD046", "MD051", "MD076",
];
const MAGO_IGNORE: &[&str] = &[
"strict-assertions",
"use-specific-assertions",
"no-redundant-variable",
"sensitive-parameter",
];
const TEST_IGNORES: &[&str] = &[
"ANN",
"D103",
"PLR2004",
"PLR0915",
"PLR0913",
"S101",
"S105",
"S106",
"S108",
"S310",
"S311",
"PT011",
"PT012",
"PERF401",
"PTH123",
"T201",
"TC001",
"TC002",
"TC003",
"INP001",
"no-unused-vars",
"no-literal-password",
"no-unescaped-output",
"RUF100",
"F401",
"F811",
"I001",
"PT018",
"ARG001",
"ARG002",
"D403",
"E713",
"UP035",
"UP012",
"RUF015",
"F541",
"EXE001",
"A001",
"N801",
];
fn toml_array(entries: &[&str]) -> String {
let inner = entries
.iter()
.map(|e| format!(" \"{e}\","))
.collect::<Vec<_>>()
.join("\n");
format!("[\n{inner}\n]")
}
pub(crate) fn scaffold_poly_config(config: &ResolvedCrateConfig, languages: &[Language]) -> Vec<GeneratedFile> {
let has = |lang: Language| languages.contains(&lang);
let extra_excludes: Vec<&str> = config.poly.exclude.iter().map(String::as_str).collect();
let all_excludes: Vec<&str> = EXCLUDES.iter().copied().chain(extra_excludes).collect();
let excludes = toml_array(&all_excludes);
let mut out = String::new();
out.push_str(&format!("[discovery]\nexclude = {excludes}\n\n"));
let md_disable = toml_array(RUMDL_DISABLE);
out.push_str(&format!("[lint.markdown.rumdl]\ndisable = {md_disable}\n\n"));
out.push_str(&format!("[fmt.markdown.rumdl]\ndisable = {md_disable}\n\n"));
if has(Language::Python) {
out.push_str(&format!(
"[lint.python.ruff]\nselect = [ \"ALL\" ]\nignore = {ignore}\n",
ignore = toml_array(RUFF_IGNORE)
));
out.push_str(
"mccabe_max_complexity = 15\n\
pydocstyle_convention = \"google\"\n\
pylint_max_args = 10\n\
pylint_max_branches = 15\n\
pylint_max_returns = 10\n\n",
);
}
if has(Language::Php) {
out.push_str(&format!(
"[lint.php.mago]\nselect = [ \"correctness\", \"security\" ]\nignore = {ignore}\nphp_version = \"8.2\"\n\n",
ignore = toml_array(MAGO_IGNORE)
));
}
out.push_str("[per-file-ignores]\n");
if has(Language::Python) {
out.push_str(
"\"**/api.py\" = [ \"F401\", \"I001\", \"TC006\", \"UP035\" ]\n\
\"**/*.pyi\" = [ \"A002\", \"F401\", \"I001\", \"PYI033\", \"TC006\", \"UP035\" ]\n\
\"**/options.py\" = [ \"F401\", \"I001\", \"RUF100\" ]\n\
\"**/__init__.py\" = [ \"I001\" ]\n",
);
}
let test_ignores = toml_array(TEST_IGNORES);
for glob in ["**/tests/**", "**/e2e/**", "**/test_apps/**"] {
out.push_str(&format!("\"{glob}\" = {test_ignores}\n"));
}
for (glob, codes) in &config.poly.per_file_ignores {
let code_refs: Vec<&str> = codes.iter().map(String::as_str).collect();
out.push_str(&format!("\"{glob}\" = {}\n", toml_array(&code_refs)));
}
out.push('\n');
out.push_str("[hooks]\nstages = [ \"pre-commit\" ]\n\n[hooks.builtin]\n");
out.push_str(&format!("polylint = {{ exclude = {excludes} }}\n"));
out.push_str(&format!("polyfmt = {{ exclude = {excludes} }}\n"));
out.push_str(&format!("file_safety = {{ exclude = {excludes} }}\n"));
out.push_str("cargo = true\n");
out.push_str("commit = { stages = [ \"commit-msg\" ] }\n");
if has(Language::Python) {
let py_dir = config.package_dir(Language::Python);
out.push_str(&format!(
"\n[hooks.pre-commit.commands.pyrefly]\nrun = \"pyrefly check {py_dir}\"\nfiles = \"{py_dir}/**/*.py\"\n"
));
}
vec![GeneratedFile {
path: PathBuf::from("poly.toml"),
content: out,
generated_header: true,
}]
}