// std/cli/paths - application-scoped config/data/cache directories for CLI scripts.
//
// Import with: import { xdg_config_home, xdg_data_home, xdg_cache_home } from "std/cli/paths"
import { is_absolute } from "std/path"
fn __app_segment(app_name: string) -> string {
let name = trim(app_name ?? "")
if name == "" || name == "." || name == ".." || contains(name, "/") || contains(name, "\\") {
throw "std/cli/paths: app_name must be a single path segment"
}
return name
}
fn __absolute_env_dir(name: string) {
let raw = harness.env.get(name)
if raw == nil {
return nil
}
let value = to_string(raw)
if trim(value) == "" || !is_absolute(value) {
return nil
}
return value
}
fn __home_dir() -> string {
let home = __absolute_env_dir("HOME")
if home != nil {
return home
}
let user_profile = __absolute_env_dir("USERPROFILE")
if user_profile != nil {
return user_profile
}
throw "std/cli/paths: HOME or USERPROFILE must be an absolute path"
}
fn __join_segments(segments: list<string>) -> string {
var out = ""
for segment in segments {
if out == "" {
out = segment
} else {
out = path_join(out, segment)
}
}
return out
}
fn __resolve_app_home(
app_name: string,
env_key: string,
xdg_segments: list<string>,
macos_segments: list<string>,
) -> string {
let app = __app_segment(app_name)
let env_root = __absolute_env_dir(env_key)
if env_root != nil {
return path_join(env_root, app)
}
let root_segments = if platform() == "darwin" {
macos_segments
} else {
xdg_segments
}
return __join_segments([__home_dir()] + root_segments + [app])
}
/**
* Return the application-specific user config directory. Honors an
* absolute `XDG_CONFIG_HOME`; otherwise uses
* `~/Library/Application Support/<app_name>` on macOS and
* `$HOME/.config/<app_name>` elsewhere. The directory is not created.
*
* @effects: [env.read]
* @allocation: heap
* @errors: ["app_name must be a single path segment", "HOME or USERPROFILE must be an absolute path"]
* @api_stability: stable
* @example: xdg_config_home("harn")
*/
pub fn xdg_config_home(app_name: string) -> string {
return __resolve_app_home(app_name, "XDG_CONFIG_HOME", [".config"], ["Library", "Application Support"])
}
/**
* Return the application-specific user data directory. Honors an
* absolute `XDG_DATA_HOME`; otherwise uses
* `~/Library/Application Support/<app_name>` on macOS and
* `$HOME/.local/share/<app_name>` elsewhere. The directory is not created.
*
* @effects: [env.read]
* @allocation: heap
* @errors: ["app_name must be a single path segment", "HOME or USERPROFILE must be an absolute path"]
* @api_stability: stable
* @example: xdg_data_home("harn")
*/
pub fn xdg_data_home(app_name: string) -> string {
return __resolve_app_home(
app_name,
"XDG_DATA_HOME",
[".local", "share"],
["Library", "Application Support"],
)
}
/**
* Return the application-specific user cache directory. Honors an
* absolute `XDG_CACHE_HOME`; otherwise uses
* `~/Library/Caches/<app_name>` on macOS and
* `$HOME/.cache/<app_name>` elsewhere. The directory is not created.
*
* @effects: [env.read]
* @allocation: heap
* @errors: ["app_name must be a single path segment", "HOME or USERPROFILE must be an absolute path"]
* @api_stability: stable
* @example: xdg_cache_home("harn")
*/
pub fn xdg_cache_home(app_name: string) -> string {
return __resolve_app_home(app_name, "XDG_CACHE_HOME", [".cache"], ["Library", "Caches"])
}