glu-cli
Version:
Git stacked branch management with GitHub integration
154 lines • 4.63 kB
JavaScript
import { cosmiconfigSync } from "cosmiconfig";
import { writeFileSync } from "fs";
import path from "path";
import os from "os";
import { defaultConfig } from "./defaults.js";
const moduleName = "glu";
const explorer = cosmiconfigSync(moduleName, {
searchStrategy: "none",
});
// Cache for loaded config
let cachedConfig = null;
let cachedConfigPath = null;
/**
* Load configuration from files with fallback to defaults
*/
export function loadConfig() {
if (cachedConfig) {
return cachedConfig;
}
try {
// Search from current directory first (project config), then home directory (user config)
let projectResult = explorer.search();
let userResult = null;
// If no project config found, search from home directory
if (!projectResult) {
userResult = explorer.search(os.homedir());
}
// Project config takes precedence over user config
const finalResult = projectResult || userResult;
const finalConfig = finalResult?.config || {};
// Cache the config path
cachedConfigPath = finalResult?.filepath || null;
// Deep merge final config with defaults
cachedConfig = mergeConfig(defaultConfig, finalConfig);
return cachedConfig;
}
catch (error) {
console.warn(`Warning: Failed to load config, using defaults: ${error}`);
cachedConfig = defaultConfig;
return cachedConfig;
}
}
/**
* Get the user config file path (uses standard cosmiconfig location)
*/
function getUserConfigPath() {
return path.join(os.homedir(), ".glurc");
}
/**
* Save configuration to user config file
*/
export function saveConfig(config) {
try {
const configPath = getUserConfigPath();
const currentConfig = loadConfig();
const mergedConfig = mergeConfig(currentConfig, config);
writeFileSync(configPath, JSON.stringify(mergedConfig, null, 2));
// Clear cache so next load picks up changes
cachedConfig = null;
console.log(`Configuration saved to ${configPath}`);
}
catch (error) {
console.error(`Failed to save config: ${error}`);
process.exit(1);
}
}
/**
* Get a specific config value with dot notation support
*/
export function getConfigValue(key) {
const config = loadConfig();
return getNestedValue(config, key);
}
/**
* Set a specific config value with dot notation support
*/
export function setConfigValue(key, value) {
const currentConfig = loadConfig();
const updatedConfig = setNestedValue(currentConfig, key, value);
saveConfig(updatedConfig);
}
/**
* Deep merge two config objects
*/
export function mergeConfig(base, override) {
const result = { ...base };
for (const [key, value] of Object.entries(override)) {
if (value !== undefined) {
if (typeof value === "object" &&
value !== null &&
!Array.isArray(value)) {
const baseValue = result[key];
if (typeof baseValue === "object" && baseValue !== null) {
result[key] = {
...baseValue,
...value,
};
}
else {
result[key] = value;
}
}
else {
result[key] = value;
}
}
}
return result;
}
/**
* Get nested value using dot notation (e.g., "remote.name")
*/
function getNestedValue(obj, path) {
return path.split(".").reduce((current, key) => current?.[key], obj);
}
/**
* Set nested value using dot notation
*/
function setNestedValue(obj, path, value) {
const keys = path.split(".");
const result = JSON.parse(JSON.stringify(obj)); // Deep clone
let current = result;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== "object") {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
return result;
}
/**
* Reset configuration to defaults
*/
export function resetConfig() {
saveConfig(defaultConfig);
console.log("Configuration reset to defaults");
}
/**
* Get the path of the currently loaded config file
*/
export function getConfigPath() {
loadConfig(); // Ensure config is loaded
return cachedConfigPath;
}
/**
* Clear config cache (useful for testing)
*/
export function clearConfigCache() {
cachedConfig = null;
cachedConfigPath = null;
}
//# sourceMappingURL=index.js.map