UNPKG

revit-cli

Version:

A scalable CLI tool for Revit communication and data manipulation

438 lines 18 kB
"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 }); const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); const chalk_1 = __importDefault(require("chalk")); const plugin_json_1 = __importDefault(require("./plugin.json")); /** * Extract elements tool */ const extractTool = { name: 'extract', description: 'Extract elements from Revit model', category: 'data', options: [ { flags: '-c, --categories <categories>', description: 'Comma-separated list of categories to extract' }, { flags: '-p, --parameters <parameters>', description: 'Comma-separated list of parameters to include' }, { flags: '-g, --geometry', description: 'Include geometry data', defaultValue: false }, { flags: '-f, --format <format>', description: 'Output format (json, csv, xml)', defaultValue: 'json' }, { flags: '-o, --output <path>', description: 'Output file path' } ], async execute(_options, context) { const { logger, revitConnector } = context; try { logger.header('ELEMENT EXTRACTION DEBUG'); logger.debug('=== EXTRACT TOOL EXECUTION START ==='); logger.debug('Raw options received:', _options); logger.debug('Context available:', { hasLogger: !!logger, hasRevitConnector: !!revitConnector, loggerLevel: logger.getLevel(), loggerFile: logger.getLogFile() }); logger.info('Starting element extraction...'); // Validate required options logger.debug('Validating extraction options...'); if (!_options['categories'] && !_options['all']) { logger.error('Validation failed: Either --categories or --all flag is required'); throw new Error('Either --categories or --all flag is required'); } logger.debug('Options validation passed'); // Build extraction options logger.debug('Building extraction options...'); const extractionOptions = { categories: _options['categories'] ? _options['categories'].split(',').map((c) => c.trim()) : undefined, parameters: _options['parameters'] ? _options['parameters'].split(',').map((p) => p.trim()) : undefined, includeGeometry: _options['geometry'] || false, limit: _options['limit'] ? parseInt(_options['limit']) : undefined }; logger.info('Extraction options built:', extractionOptions); logger.debug('Categories to extract:', extractionOptions.categories); logger.debug('Parameters to include:', extractionOptions.parameters); logger.debug('Include geometry:', extractionOptions.includeGeometry); logger.debug('Element limit:', extractionOptions.limit); // Test connection before extraction logger.debug('Testing Revit connection before extraction...'); const connectionStatus = await revitConnector.getConnectionStatus(); logger.debug('Connection status:', connectionStatus); if (!connectionStatus.connected) { logger.error('Revit connection failed:', connectionStatus); throw new Error(`Cannot connect to Revit: ${connectionStatus.error || 'Unknown error'}`); } logger.debug('Revit connection verified successfully'); // Extract elements logger.debug('Calling revitConnector.extractElements...'); const startTime = Date.now(); const elements = await revitConnector.extractElements(extractionOptions); const endTime = Date.now(); logger.debug(`Element extraction completed in ${endTime - startTime}ms`); logger.debug(`Extracted ${elements?.length || 0} elements`); if (elements && elements.length > 0) { logger.debug('Sample extracted element:', elements[0]); } // Handle output logger.debug('Processing output options...'); if (_options['output']) { logger.debug('Saving to file:', _options['output']); const format = _options['format'] || 'json'; logger.debug('Output format:', format); await saveExtractedData(elements, _options['output'], format, logger); } else { logger.debug('Displaying results to console'); // Display summary or full data if (_options['summary']) { logger.debug('Showing summary view'); displayExtractionSummary(elements); } else { logger.debug('Showing full data'); console.log(JSON.stringify(elements, null, 2)); } } logger.success(`Successfully extracted ${elements.length} elements`); logger.debug('=== EXTRACT TOOL EXECUTION END ==='); } catch (error) { logger.error('=== EXTRACT TOOL EXECUTION FAILED ==='); logger.error('Error details:', { message: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, name: error instanceof Error ? error.name : undefined }); logger.error('Element extraction failed:', error); throw error; } } }; /** * List categories tool */ const listCategoriesTool = { name: 'categories', description: 'List all available Revit categories', category: 'info', async execute(_options, context) { const { logger, revitConnector } = context; try { logger.header('CATEGORIES LIST DEBUG'); logger.debug('=== CATEGORIES TOOL EXECUTION START ==='); logger.debug('Raw options received:', _options); logger.debug('Context available:', { hasLogger: !!logger, hasRevitConnector: !!revitConnector, loggerLevel: logger.getLevel(), loggerFile: logger.getLogFile() }); logger.info('Fetching Revit categories...'); // Test connection before fetching categories logger.debug('Testing Revit connection before fetching categories...'); const connectionStatus = await revitConnector.getConnectionStatus(); logger.debug('Connection status:', connectionStatus); if (!connectionStatus.connected) { logger.error('Revit connection failed:', connectionStatus); throw new Error(`Cannot connect to Revit: ${connectionStatus.error || 'Unknown error'}`); } logger.debug('Revit connection verified successfully'); logger.debug('Calling revitConnector.getCategories...'); const startTime = Date.now(); const result = await revitConnector.getCategories(); const endTime = Date.now(); logger.debug(`Categories fetch completed in ${endTime - startTime}ms`); if (!result.success) { logger.error('Categories fetch failed:', result.error); throw new Error(result.error || 'Failed to get categories'); } const categories = result.data || []; logger.debug(`Retrieved ${categories?.length || 0} categories`); if (categories && categories.length > 0) { logger.debug('Sample category:', categories[0]); logger.debug('All categories:', categories); } console.log(chalk_1.default.blue('\nAvailable Categories:')); // Handle both string array and object array formats if (categories.length > 0) { const categoryNames = categories.map((category, index) => { // If category is an object with name property, extract the name if (typeof category === 'object' && category.name) { const categoryName = category.name; const elementCount = category.elementCount || 0; console.log(` ${index + 1}. ${chalk_1.default.green(categoryName)} ${chalk_1.default.gray(`(${elementCount} elements)`)}`); return categoryName; } // If category is a string, use it directly else if (typeof category === 'string') { console.log(` ${index + 1}. ${chalk_1.default.green(category)}`); return category; } return null; }).filter(Boolean); logger.success(`Found ${categoryNames.length} categories`); } else { logger.success('Found 0 categories'); } logger.debug('=== CATEGORIES TOOL EXECUTION END ==='); } catch (error) { logger.error('=== CATEGORIES TOOL EXECUTION FAILED ==='); logger.error('Error details:', { message: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, name: error instanceof Error ? error.name : undefined }); logger.error('Failed to list categories:', error); throw error; } } }; /** * Project info tool */ const projectInfoTool = { name: 'info', description: 'Get Revit project information', category: 'info', async execute(_options, context) { const { logger, revitConnector } = context; try { logger.info('Fetching project information...'); const result = await revitConnector.getProjectInfo(); if (!result.success) { throw new Error(result.error || 'Failed to get project info'); } const projectInfo = result.data; console.log(chalk_1.default.blue('\nProject Information:')); console.log(JSON.stringify(projectInfo, null, 2)); logger.success('Project information retrieved successfully'); } catch (error) { logger.error('Failed to get project info:', error); throw error; } } }; /** * Parse file tool */ const parseTool = { name: 'parse', description: 'Parse and analyze Revit data files', category: 'data', options: [ { flags: '-f, --file <path>', description: 'Path to the file to parse' }, { flags: '-t, --type <type>', description: 'File type (json, csv, xml)', defaultValue: 'json' }, { flags: '-s, --summary', description: 'Show summary statistics', defaultValue: false } ], async execute(_options, context) { const { logger } = context; try { if (!_options['file']) { throw new Error('File path is required. Use -f or --file option.'); } const filePath = path.resolve(_options['file']); if (!await fs.pathExists(filePath)) { throw new Error(`File not found: ${filePath}`); } logger.info(`Parsing file: ${filePath}`); const fileContent = await fs.readFile(filePath, 'utf-8'); let data; // Parse based on file type switch (_options['type'].toLowerCase()) { case 'json': data = JSON.parse(fileContent); break; case 'csv': // Simple CSV parsing (for demo purposes) const lines = fileContent.split('\n'); const headers = lines[0]?.split(',') || []; data = lines.slice(1).map(line => { const values = line.split(','); const obj = {}; headers.forEach((header, index) => { obj[header.trim()] = values[index]?.trim(); }); return obj; }); break; default: throw new Error(`Unsupported file type: ${_options['type']}`); } if (_options['summary']) { displayDataSummary(data); } else { console.log(chalk_1.default.blue('\nParsed Data:')); console.log(JSON.stringify(data, null, 2)); } logger.success('File parsed successfully'); } catch (error) { logger.error('Failed to parse file:', error); throw error; } } }; /** * Helper function to save extracted data */ async function saveExtractedData(data, outputPath, format, logger) { const resolvedPath = path.resolve(outputPath); await fs.ensureDir(path.dirname(resolvedPath)); let content; switch (format.toLowerCase()) { case 'json': content = JSON.stringify(data, null, 2); break; case 'csv': if (data.length === 0) { content = ''; } else { const headers = Object.keys(data[0] || {}); const csvRows = [headers.join(',')]; data.forEach(item => { const row = headers.map(header => { const value = item[header]; return typeof value === 'string' && value.includes(',') ? `"${value}"` : value; }); csvRows.push(row.join(',')); }); content = csvRows.join('\n'); } break; default: throw new Error(`Unsupported format: ${format}`); } await fs.writeFile(resolvedPath, content, 'utf-8'); logger.success(`Data saved to: ${resolvedPath}`); } /** * Helper function to display extraction summary */ function displayExtractionSummary(elements) { console.log(chalk_1.default.blue('\nExtraction Summary:')); console.log(` Total Elements: ${chalk_1.default.green(elements.length)}`); if (elements.length > 0) { // Group by category const categoryCount = {}; elements.forEach(element => { const category = element.category || 'Unknown'; categoryCount[category] = (categoryCount[category] || 0) + 1; }); console.log('\n By Category:'); Object.entries(categoryCount).forEach(([category, count]) => { console.log(` ${category}: ${chalk_1.default.yellow(count)}`); }); // Show sample element console.log('\n Sample Element:'); console.log(JSON.stringify(elements[0], null, 4)); } } /** * Helper function to display data summary */ function displayDataSummary(data) { console.log(chalk_1.default.blue('\nData Summary:')); if (Array.isArray(data)) { console.log(` Type: Array`); console.log(` Length: ${chalk_1.default.green(data.length)}`); if (data.length > 0) { console.log(` Sample Item:`); console.log(JSON.stringify(data[0], null, 4)); } } else if (typeof data === 'object' && data !== null) { console.log(` Type: Object`); console.log(` Keys: ${chalk_1.default.green(Object.keys(data).length)}`); console.log(` Properties: ${Object.keys(data).join(', ')}`); } else { console.log(` Type: ${typeof data}`); console.log(` Value: ${data}`); } } /** * Core plugin definition */ const corePlugin = { metadata: plugin_json_1.default, tools: [ extractTool, listCategoriesTool, projectInfoTool, parseTool ], async initialize(context) { context.logger.debug('Core plugin initialized'); }, async cleanup() { // Cleanup if needed } }; exports.default = corePlugin; //# sourceMappingURL=index.js.map