UNPKG

skaya

Version:

CLI SDK for full-stack automation: scaffold frontend, backend & blockchain. Future-ready for Web3, integrations, server components & logging.

270 lines (269 loc) 13.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.saveProjectConfig = saveProjectConfig; exports.saveProjectComponentConfig = saveProjectComponentConfig; exports.getProjectComponentConfig = getProjectComponentConfig; exports.updateComponentReferences = updateComponentReferences; exports.logComponentCreation = logComponentCreation; exports.readConfig = readConfig; exports.readComponentImportConfig = readComponentImportConfig; // src/utils/configLogger.ts const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const CONFIG_FILE = 'skaya.config.json'; const LOG_FILE = 'Skayalogs.log'; const DEFAULT_PROJECT_NAME = 'SkayaProject'; // Moved to a constant /** * Saves project type (frontend/backend/blockchain) to skaya.config.json. * This function creates or updates the top-level project configuration. * @param projectType - Project type (e.g., ProjectType.Frontend, ProjectType.Backend) * @param name - Name of the project * @param template - Template to use (optional, defaults to "custom") */ function saveProjectConfig(projectType, name, template) { return __awaiter(this, void 0, void 0, function* () { var _a; try { const configPath = path_1.default.join(process.cwd(), CONFIG_FILE); // Corrected path to be in current working directory console.log("Saving project config to:", configPath); let config = {}; try { const fileContent = yield fs_1.promises.readFile(configPath, 'utf-8'); if (fileContent.trim().length > 0) { config = JSON.parse(fileContent); } } catch (error) { if (error.code !== 'ENOENT') { throw new Error(`Error reading config file: ${error.message}`); } console.log(`Config file ${CONFIG_FILE} not found, creating a new one.`); } if (config[projectType]) { console.log(`Project type ${projectType} already exists in config. Updating.`); } config[projectType] = { name, template: template || "custom", createdAt: new Date().toISOString(), components: ((_a = config[projectType]) === null || _a === void 0 ? void 0 : _a.components) || {} // Preserve existing components if updating }; yield fs_1.promises.writeFile(configPath, JSON.stringify(config, null, 2)); } catch (error) { throw error; } }); } /** * Saves component-specific configuration for a given project type. * This allows storing details about components within a project (e.g., 'auth', 'database'). * The configuration now supports tracking component relationships through imports. * @param projectType - The ProjectType (e.g., ProjectType.Frontend) * @param componentType - The ComponentType (e.g., ComponentType.UI_COMPONENT, ComponentType.API_COMPONENT) * @param componentName - The name of the component (e.g., "auth", "paymentGateway") * @param componentDetails - The configuration object for the specific component */ function saveProjectComponentConfig(projectType, componentType, componentName, componentDetails // Partial to allow for updates ) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; try { let config = {}; const configPath = path_1.default.join(process.cwd(), CONFIG_FILE); // Try to read existing config try { const data = yield fs_1.promises.readFile(configPath, 'utf-8'); config = JSON.parse(data); } catch (error) { if (error.code === 'ENOENT') { console.log(`Config file ${CONFIG_FILE} not found for component config, creating a new one.`); } else { console.warn(`Warning: Could not parse existing config file for component config, creating new one. Error: ${error.message}`); } } // Ensure the project type entry exists if (!config[projectType]) { config[projectType] = { name: `${projectType}${DEFAULT_PROJECT_NAME}`, template: "custom", createdAt: new Date().toISOString(), components: {} }; console.log(`Initialized new entry for project type: ${projectType}`); } // Ensure the 'components' property exists within the project type if (!config[projectType].components) { config[projectType].components = {}; console.log(`Initialized 'components' property for project type: ${projectType}`); } // Get existing component config to merge const existingComponentConfig = config[projectType].components[componentName] || { source: 'template', // Default source if new files: [], componentType: componentType, // Set initial componentType savedAt: new Date().toISOString(), imports: [], usedBy: [] }; // Process imports to add componentType if missing (though it should ideally be provided or inferred during generation) // For now, we'll assume `imports` within `componentDetails` already has `componentType` if needed, // or it will be determined by the system later. const processedImports = (_a = componentDetails.imports) === null || _a === void 0 ? void 0 : _a.map(imp => (Object.assign(Object.assign({}, imp), { componentType: imp.componentType || undefined // Assuming it might be set or not }))); // Assign the component configuration, merging with existing data config[projectType].components[componentName] = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, existingComponentConfig), componentDetails), { componentType: componentType }), (processedImports && { imports: processedImports })), { savedAt: existingComponentConfig.savedAt || new Date().toISOString(), updatedAt: new Date().toISOString() // Always update updatedAt }); // Write the updated config back to file yield fs_1.promises.writeFile(configPath, JSON.stringify(config, null, 2)); // Update reverse references if imports changed or component is new if ((processedImports === null || processedImports === void 0 ? void 0 : processedImports.length) || ((_b = existingComponentConfig.imports) === null || _b === void 0 ? void 0 : _b.length)) { yield updateComponentReferences(projectType, componentName, processedImports || [], // New imports existingComponentConfig.imports || [] // Old imports ); } } catch (error) { console.error(`❌ Failed to save component '${componentName}' configuration for '${projectType}':`, error); throw error; } }); } /** * Retrieves the configuration for a specific component. * @param projectType - The ProjectType (e.g., ProjectType.Frontend) * @param componentName - The name of the component (e.g., "auth") * @returns The ComponentConfig object or undefined if not found. */ function getProjectComponentConfig(projectType, componentName) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; try { const config = yield readConfig(); return (_b = (_a = config[projectType]) === null || _a === void 0 ? void 0 : _a.components) === null || _b === void 0 ? void 0 : _b[componentName]; } catch (error) { console.error(`❌ Failed to get configuration for component '${componentName}' in '${projectType}':`, error); return undefined; } }); } // Helper function to update references in imported components function updateComponentReferences(projectType_1, sourceComponent_1, newImports_1) { return __awaiter(this, arguments, void 0, function* (projectType, sourceComponent, newImports, oldImports = []) { var _a; const config = yield readConfig(); const projectComponents = (_a = config[projectType]) === null || _a === void 0 ? void 0 : _a.components; if (!projectComponents) { console.warn(`No components found for project type ${projectType}.`); return; } // Remove old references for (const oldImp of oldImports) { if (projectComponents[oldImp.name]) { const importedComp = projectComponents[oldImp.name]; if (importedComp.usedBy) { importedComp.usedBy = importedComp.usedBy.filter((comp) => comp !== sourceComponent); } } } // Add new references for (const newImp of newImports) { if (projectComponents[newImp.name]) { const importedComp = projectComponents[newImp.name]; if (!importedComp.usedBy) { importedComp.usedBy = []; } if (!importedComp.usedBy.includes(sourceComponent)) { importedComp.usedBy.push(sourceComponent); } } } // Save the updated config const configPath = path_1.default.join(process.cwd(), CONFIG_FILE); yield fs_1.promises.writeFile(configPath, JSON.stringify(config, null, 2)); }); } /** * Logs component creation details to the log file. * @param params - Component creation parameters */ function logComponentCreation(params) { return __awaiter(this, void 0, void 0, function* () { try { const logEntry = Object.assign({ timestamp: params.timestamp || new Date().toISOString() }, params); const logLine = JSON.stringify(logEntry) + '\n'; // Append to log file (creates it if doesn't exist) yield fs_1.promises.appendFile(LOG_FILE, logLine); } catch (error) { console.error('❌ Failed to log component creation:', error); throw error; } }); } /** * Reads the configuration file. * @returns A Promise that resolves to the Config object. Returns an empty object if the file doesn't exist or is invalid. */ function readConfig() { return __awaiter(this, void 0, void 0, function* () { try { const configPath = path_1.default.join(process.cwd(), CONFIG_FILE); // Consistent path with save functions const data = yield fs_1.promises.readFile(configPath, 'utf-8'); return JSON.parse(data); } catch (error) { if (error.code === 'ENOENT') { // console.log(`Config file ${CONFIG_FILE} not found. Returning empty config.`); } else { console.error('❌ Failed to read configuration file:', error); } return {}; // Return empty object if file not found or parsing fails } }); } /** * Reads the component import configuration from the config file. * Note: This function assumes that the `ComponentImportConfig` might be stored directly * as a top-level property (e.g., `config.componentImports`). If component import configs * are expected to be nested within project types, this function would need adjustment. * @returns A Promise that resolves to the ComponentImportConfig object. */ function readComponentImportConfig() { return __awaiter(this, void 0, void 0, function* () { try { const configPath = path_1.default.join(process.cwd(), CONFIG_FILE); // Consistent path with save functions const data = yield fs_1.promises.readFile(configPath, 'utf-8'); const config = JSON.parse(data); // This line assumes a top-level 'componentImports' key in your config. // If component import configurations are stored differently (e.g., within a project type's 'components'), // this logic would need to be updated. return config.componentImports || {}; } catch (error) { if (error.code === 'ENOENT') { // console.log(`Component import config file ${CONFIG_FILE} not found. Returning empty config.`); } else { console.error('❌ Failed to read component import configuration:', error); } return {}; // Return empty object if file not found or parsing fails } }); }