use std::path::PathBuf;
use crate::config;
use crate::scan;
use crate::{Error, Options};
#[derive(Debug, serde::Serialize)]
pub struct BuiltinVocabulary {
pub id: &'static str,
pub kind: &'static str,
pub case: &'static str,
pub source: &'static str,
pub source_version: &'static str,
#[serde(skip)]
builtin: config::Builtin,
}
const BUILTINS: &[BuiltinVocabulary] = &[
BuiltinVocabulary {
id: "english",
kind: "natural-language",
case: "unicode-lowercase",
source: "https://github.com/en-wl/wordlist",
source_version: include_str!("../data/english/ESDB").trim_ascii(),
builtin: config::Builtin::English,
},
BuiltinVocabulary {
id: "sql@2023",
kind: "technical",
case: "sensitive",
source: "https://github.com/postgres/postgres",
source_version: include_str!("../data/sql/POSTGRESQL").trim_ascii(),
builtin: config::Builtin::Sql2023,
},
BuiltinVocabulary {
id: "wasi@preview1",
kind: "technical",
case: "sensitive",
source: "https://github.com/WebAssembly/WASI",
source_version: include_str!("../data/wasi/WASI").trim_ascii(),
builtin: config::Builtin::WasiPreview1,
},
BuiltinVocabulary {
id: "wasm@3.0",
kind: "technical",
case: "sensitive",
source: "https://github.com/WebAssembly/spec",
source_version: include_str!("../data/wasm/SPEC").trim_ascii(),
builtin: config::Builtin::Wasm3,
},
BuiltinVocabulary {
id: "android@36",
kind: "technical",
case: "sensitive",
source: "https://android.googlesource.com/platform/frameworks/base",
source_version: include_str!("../data/android/AOSP").trim_ascii(),
builtin: config::Builtin::Android36,
},
BuiltinVocabulary {
id: "uikit@27.1",
kind: "technical",
case: "sensitive",
source: "https://github.com/dotnet/macios",
source_version: include_str!("../data/uikit/MACIOS").trim_ascii(),
builtin: config::Builtin::Uikit27_1,
},
BuiltinVocabulary {
id: "posix@2017",
kind: "technical",
case: "sensitive",
source: "https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/man-pages-posix",
source_version: include_str!("../data/posix/MAN_PAGES_POSIX").trim_ascii(),
builtin: config::Builtin::Posix2017,
},
BuiltinVocabulary {
id: "web-api@2026-10",
kind: "technical",
case: "sensitive",
source: "https://github.com/mdn/browser-compat-data",
source_version: include_str!("../data/bcd/BCD").trim_ascii(),
builtin: config::Builtin::WebApi2026_10,
},
BuiltinVocabulary {
id: "python@3.15",
kind: "technical",
case: "sensitive",
source: "https://github.com/python/cpython",
source_version: include_str!("../data/python/CPYTHON").trim_ascii(),
builtin: config::Builtin::Python3_15,
},
BuiltinVocabulary {
id: "javascript@2026-10",
kind: "technical",
case: "sensitive",
source: "https://github.com/mdn/browser-compat-data",
source_version: include_str!("../data/bcd/BCD").trim_ascii(),
builtin: config::Builtin::Javascript2026_10,
},
BuiltinVocabulary {
id: "svg@2026-10",
kind: "technical",
case: "sensitive",
source: "https://github.com/mdn/browser-compat-data",
source_version: include_str!("../data/bcd/BCD").trim_ascii(),
builtin: config::Builtin::Svg2026_10,
},
BuiltinVocabulary {
id: "postgres@18",
kind: "technical",
case: "sensitive",
source: "https://github.com/postgres/postgres",
source_version: include_str!("../data/postgres/POSTGRESQL").trim_ascii(),
builtin: config::Builtin::Postgres18,
},
BuiltinVocabulary {
id: "sqlite@3.54",
kind: "technical",
case: "sensitive",
source: "https://github.com/sqlite/sqlite",
source_version: include_str!("../data/sqlite/SQLITE").trim_ascii(),
builtin: config::Builtin::Sqlite3_54,
},
];
#[must_use]
pub fn available() -> &'static [BuiltinVocabulary] {
BUILTINS
}
pub(crate) fn id(builtin: config::Builtin) -> &'static str {
BUILTINS
.iter()
.find(|vocabulary| vocabulary.builtin == builtin)
.expect("the catalog lists every built-in")
.id
}
#[derive(Debug, serde::Serialize)]
pub struct CustomVocabulary {
pub path: PathBuf,
pub kind: &'static str,
pub case: &'static str,
pub format_version: u32,
}
#[derive(Debug, serde::Serialize)]
pub struct EffectiveVocabularies {
pub config: PathBuf,
pub rust_stdlib: bool,
pub builtins: Vec<&'static BuiltinVocabulary>,
pub files: Vec<CustomVocabulary>,
}
pub fn effective(options: &Options) -> Result<EffectiveVocabularies, Error> {
let repo = scan::repository(options)?;
let (_, workspace_dir) = scan::workspace(options, &repo)?;
let (config_path, selection) = scan::selected_config(options, &workspace_dir)?;
let builtins = BUILTINS
.iter()
.filter(|builtin| selection.selects(builtin.builtin))
.collect();
let files = config::load_custom(&config_path, &selection)?
.into_iter()
.map(|file| CustomVocabulary {
path: file.path,
kind: file.kind.as_str(),
case: file.case.as_str(),
format_version: file.format_version,
})
.collect();
Ok(EffectiveVocabularies {
config: config_path,
rust_stdlib: true,
builtins,
files,
})
}