revit-cli
Version:
A scalable CLI tool for Revit communication and data manipulation
382 lines • 13.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigManager = void 0;
const fs = __importStar(require("fs-extra"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const yaml = __importStar(require("yaml"));
const inquirer_1 = __importDefault(require("inquirer"));
const logger_1 = require("../utils/logger");
/**
* Manages configuration for the CLI and tools
*/
class ConfigManager {
constructor() {
this.defaultConfig = {
revit: {
apiUrl: 'http://localhost:8080',
timeout: 30000,
retries: 3
},
plugins: {
directories: [
path.join(process.cwd(), 'plugins'),
path.join(os.homedir(), '.revit-cli', 'plugins')
],
disabled: []
},
logging: {
level: 'info'
},
tools: {}
};
this.logger = new logger_1.Logger();
this.configPath = this.getDefaultConfigPath();
this.config = { ...this.defaultConfig };
}
/**
* Initialize the configuration manager
*/
async initialize() {
this.logger.debug('Initializing Configuration Manager...');
try {
await this.ensureConfigDirectory();
await this.loadConfig();
this.logger.debug('Configuration Manager initialized');
}
catch (error) {
this.logger.error('Failed to initialize Configuration Manager:', error);
throw error;
}
}
/**
* Get the default configuration file path
*/
getDefaultConfigPath() {
const configDir = path.join(os.homedir(), '.revit-cli');
return path.join(configDir, 'config.json');
}
/**
* Ensure the configuration directory exists
*/
async ensureConfigDirectory() {
const configDir = path.dirname(this.configPath);
await fs.ensureDir(configDir);
}
/**
* Load configuration from file
*/
async loadConfig() {
try {
if (await fs.pathExists(this.configPath)) {
const fileContent = await fs.readFile(this.configPath, 'utf-8');
let loadedConfig;
// Support both JSON and YAML formats
if (this.configPath.endsWith('.yaml') || this.configPath.endsWith('.yml')) {
loadedConfig = yaml.parse(fileContent);
}
else {
loadedConfig = JSON.parse(fileContent);
}
// Merge with default config
this.config = this.mergeConfig(this.defaultConfig, loadedConfig);
this.logger.debug(`Configuration loaded from ${this.configPath}`);
}
else {
// Create default config file
await this.saveConfig();
this.logger.info(`Created default configuration at ${this.configPath}`);
}
}
catch (error) {
this.logger.warn(`Failed to load config from ${this.configPath}, using defaults:`, error);
this.config = { ...this.defaultConfig };
}
}
/**
* Save configuration to file
*/
async saveConfig() {
try {
await this.ensureConfigDirectory();
let content;
if (this.configPath.endsWith('.yaml') || this.configPath.endsWith('.yml')) {
content = yaml.stringify(this.config, { indent: 2 });
}
else {
content = JSON.stringify(this.config, null, 2);
}
await fs.writeFile(this.configPath, content, 'utf-8');
this.logger.debug(`Configuration saved to ${this.configPath}`);
}
catch (error) {
this.logger.error('Failed to save configuration:', error);
throw error;
}
}
/**
* Deep merge two configuration objects
*/
mergeConfig(defaultConfig, userConfig) {
const merged = { ...defaultConfig };
for (const [key, value] of Object.entries(userConfig)) {
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
merged[key] = {
...merged[key],
...value
};
}
else {
merged[key] = value;
}
}
return merged;
}
/**
* Get the current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Get a specific configuration value
*/
get(path, defaultValue) {
const keys = path.split('.');
let current = this.config;
for (const key of keys) {
if (current && typeof current === 'object' && key in current) {
current = current[key];
}
else {
return defaultValue;
}
}
return current;
}
/**
* Set a configuration value
*/
async set(path, value) {
const keys = path.split('.');
let current = this.config;
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];
}
const lastKey = keys[keys.length - 1];
current[lastKey] = value;
await this.saveConfig();
this.logger.debug(`Configuration updated: ${path} = ${JSON.stringify(value)}`);
}
/**
* Interactive configuration editor
*/
async editConfig() {
try {
const questions = [
{
type: 'input',
name: 'revitApiUrl',
message: 'Revit API URL:',
default: this.config.revit?.apiUrl || ''
},
{
type: 'number',
name: 'revitTimeout',
message: 'Revit API Timeout (ms):',
default: this.config.revit?.timeout || 30000
},
{
type: 'number',
name: 'revitRetryAttempts',
message: 'Revit API Retry Attempts:',
default: this.config.revit?.retries || 3
},
{
type: 'list',
name: 'loggingLevel',
message: 'Logging Level:',
choices: ['debug', 'info', 'warn', 'error'],
default: this.config.logging?.level || 'info'
},
{
type: 'input',
name: 'loggingFile',
message: 'Log File Path (optional):',
default: this.config.logging?.file || ''
}
];
const answers = await inquirer_1.default.prompt(questions);
// Update configuration
if (this.config.revit) {
this.config.revit.apiUrl = answers.revitApiUrl;
this.config.revit.timeout = answers.revitTimeout;
this.config.revit.retries = answers.revitRetryAttempts;
}
if (this.config.logging) {
this.config.logging.level = answers.loggingLevel;
if (answers.loggingFile) {
this.config.logging.file = answers.loggingFile;
}
}
await this.saveConfig();
console.log('Configuration updated successfully!');
}
catch (error) {
this.logger.error('Failed to edit configuration:', error);
throw error;
}
}
/**
* Set custom configuration file path
*/
setConfigPath(configPath) {
this.configPath = path.resolve(configPath);
this.logger.debug(`Configuration path set to: ${this.configPath}`);
}
/**
* Reset configuration to defaults
*/
async resetToDefaults() {
this.config = { ...this.defaultConfig };
await this.saveConfig();
this.logger.info('Configuration reset to defaults');
}
/**
* Interactive configuration editing
*/
async editInteractive() {
const inquirer = await Promise.resolve().then(() => __importStar(require('inquirer')));
const questions = [
{
type: 'input',
name: 'revitApiUrl',
message: 'Revit API URL:',
default: this.config.revit?.apiUrl || ''
},
{
type: 'number',
name: 'revitTimeout',
message: 'Revit API Timeout (ms):',
default: this.config.revit?.timeout || 30000
},
{
type: 'number',
name: 'revitRetryAttempts',
message: 'Revit API Retry Attempts:',
default: this.config.revit?.retries || 3
},
{
type: 'list',
name: 'loggingLevel',
message: 'Logging Level:',
choices: ['debug', 'info', 'warn', 'error'],
default: this.config.logging?.level || 'info'
},
{
type: 'input',
name: 'loggingFile',
message: 'Log File Path (optional):',
default: this.config.logging?.file || ''
}
];
const answers = await inquirer.default.prompt(questions);
// Update configuration
if (this.config.revit) {
this.config.revit.apiUrl = answers.revitApiUrl;
this.config.revit.timeout = answers.revitTimeout;
this.config.revit.retries = answers.revitRetryAttempts;
}
if (this.config.logging) {
this.config.logging.level = answers.loggingLevel;
if (answers.loggingFile) {
this.config.logging.file = answers.loggingFile;
}
}
await this.saveConfig();
console.log('Configuration updated successfully!');
}
/**
* Validate configuration
*/
validateConfig() {
const errors = [];
// Validate Revit configuration
if (!this.config.revit?.apiUrl) {
errors.push('Revit API URL is required');
}
if (this.config.revit?.timeout && this.config.revit.timeout < 1000) {
errors.push('Revit API timeout must be at least 1000ms');
}
if (this.config.revit?.retries && this.config.revit.retries < 0) {
errors.push('Revit API retry attempts must be non-negative');
}
// Validate logging configuration
const validLogLevels = ['debug', 'info', 'warn', 'error'];
if (this.config.logging?.level && !validLogLevels.includes(this.config.logging.level)) {
errors.push(`Invalid logging level: ${this.config.logging.level}`);
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Get tool-specific configuration
*/
getToolConfig(toolName) {
return this.config.tools?.[toolName] || {};
}
/**
* Set tool-specific configuration
*/
async setToolConfig(toolName, config) {
if (!this.config.tools) {
this.config.tools = {};
}
this.config.tools[toolName] = config;
await this.saveConfig();
}
}
exports.ConfigManager = ConfigManager;
//# sourceMappingURL=config-manager.js.map