skaya
Version:
CLI SDK for full-stack automation: scaffold frontend, backend & blockchain. Future-ready for Web3, integrations, server components & logging.
272 lines (271 loc) • 13.5 kB
JavaScript
;
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 __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.loadComponentConfig = void 0;
exports.scanExistingComponents = scanExistingComponents;
exports.getDefaultFolderForComponentType = getDefaultFolderForComponentType;
exports.getDefaultTemplateDirectory = getDefaultTemplateDirectory;
exports.getFilesInFolder = getFilesInFolder;
const path_1 = __importStar(require("path"));
const configLogger_1 = require("./configLogger");
const fs_1 = require("fs");
const enums_1 = require("../types/enums");
const TemplateService_1 = __importDefault(require("../../src/services/TemplateService"));
/**
* Scans existing components in the project
*/
function scanExistingComponents(projectType, componentType) {
return __awaiter(this, void 0, void 0, function* () {
try {
const componentsPath = `${process.cwd()}/${yield getDefaultFolderForComponentType(projectType, componentType)}`;
try {
// Verify the directory exists first
yield fs_1.promises.access(componentsPath);
const files = yield fs_1.promises.readdir(componentsPath, { withFileTypes: true });
// Get all component directories (ignore files)
const componentDirs = files
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name);
// Array to hold components with their data
const componentsWithData = [];
for (const dir of componentDirs) {
// --- IMPROVED CONDITION HERE ---
// If componentType is ApiType, skip the 'redux' folder completely
if (dir === "redux") {
continue; // Skip to the next directory in the loop
}
const componentDirPath = path_1.default.join(componentsPath, dir);
let componentFiles;
try {
componentFiles = yield fs_1.promises.readdir(componentDirPath);
}
catch (error) {
console.error(`❌ Failed to read directory ${dir}:`, error);
continue;
}
// More flexible main file detection
const possibleMainFiles = TemplateService_1.default.getBaseTemplateFiles(componentType)
.map((file) => file.replace(new RegExp(componentType, "gi"), dir))
.concat([
// Add common fallbacks
`${dir}.tsx`,
`${dir}.ts`,
`${dir}.jsx`,
`${dir.charAt(0).toUpperCase() + dir.slice(1)}.tsx`,
// Handle case where dir ends with "Page" (e.g., "asffsPage" -> "asffs.tsx")
...(dir.toLowerCase().endsWith("page")
? [`${dir.slice(0, -4)}.tsx`]
: []),
"index.tsx",
"index.ts",
]);
const mainFile = possibleMainFiles.find((file) => componentFiles.includes(file) ||
componentFiles.includes(path_1.default.basename(file)));
if (mainFile) {
try {
const filePath = path_1.default.join(componentDirPath, mainFile);
const fileContent = yield fs_1.promises.readFile(filePath, "utf-8");
componentsWithData.push({
name: dir,
data: fileContent,
});
}
catch (error) {
console.error(`❌ Failed to read component file in ${dir}: ${error}`);
}
}
else {
console.warn(`⚠️ No main file found for component ${dir} in ${componentDirPath}`);
console.warn(`ℹ️ Looked for:`, possibleMainFiles);
console.warn(`ℹ️ Found files:`, componentFiles);
}
}
return componentsWithData;
}
catch (error) {
console.error(`❌ Failed to read components directory for ${componentType}. Unable to send extra components to ai.`);
return [];
}
}
catch (error) {
console.error(error instanceof Error ? error.message : String(error));
return [];
}
});
}
/**
* Gets the default folder for a component type
* @param {ProjectType} projectType - The project type (frontend/backend)
* @param {ComponentType} componentType - The component type
* @returns {Promise<string>} The default folder path
*/
function getDefaultFolderForComponentType(projectType, componentType, fileName) {
return __awaiter(this, void 0, void 0, function* () {
try {
const config = yield (0, configLogger_1.readConfig)();
if (!config) {
throw new Error("Configuration not found.");
}
// Validate project type
if (!Object.values(enums_1.ProjectType).includes(projectType)) {
throw new Error(`Invalid project type: ${projectType}`);
}
// Initialize missing configurations with defaults
const configMap = {
[enums_1.ProjectType.FRONTEND]: config === null || config === void 0 ? void 0 : config.frontend,
[enums_1.ProjectType.BACKEND]: config === null || config === void 0 ? void 0 : config.backend,
[enums_1.ProjectType.BLOCKCHAIN]: config === null || config === void 0 ? void 0 : config.blockchain,
};
if (!configMap[projectType]) {
console.warn(`${projectType} config not found. Setting default or add your folder.`);
// Update both the config map and the original config
configMap[projectType] = { name: `${projectType}SkayaProject`, template: "" };
}
// Get base source path
const projectConfig = configMap[projectType];
const baseSrcPath = `${(projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.name) || `${projectType}SkayaProject`}/src`;
// Handle component-specific paths
if (!componentType) {
return baseSrcPath;
}
const componentTypeMap = {
[enums_1.FrontendComponentType.PAGE]: `${enums_1.FrontendComponentType.PAGE}s`,
[enums_1.FrontendComponentType.COMPONENT]: `${enums_1.FrontendComponentType.COMPONENT}s`,
[enums_1.FrontendComponentType.API]: `${enums_1.FrontendComponentType.API}s`,
[enums_1.BackendComponentType.ROUTE]: `${enums_1.BackendComponentType.ROUTE}s`,
[enums_1.BackendComponentType.CONTROLLER]: `${enums_1.BackendComponentType.CONTROLLER}s`,
[enums_1.BlokchainComponentType.CONTRACT]: `${enums_1.BlokchainComponentType.CONTRACT}s`,
};
const componentPath = componentTypeMap[componentType];
if (!componentPath) {
console.warn(`Unknown component type: ${componentType}. Returning base path.`);
return baseSrcPath;
}
if (fileName) {
return `${baseSrcPath}/${componentPath}/${fileName}`;
}
return `${baseSrcPath}/${componentPath}`;
}
catch (error) {
console.error(`Error in getDefaultFolder: ${error instanceof Error ? error.message : error}`);
throw error; // Re-throw to allow caller to handle
}
});
}
/**
* Gets the template directory path for a given project and component type
* @param projectType The project type (frontend/backend)
* @param componentType The component type
* @returns The full path to the template directory
*/
function getDefaultTemplateDirectory(projectType, componentType) {
return path_1.default.join(__dirname, "..", "templates", projectType.toLowerCase(), componentType);
}
// Add this to componentUtils.ts
const loadComponentConfig = () => {
try {
const configPath = (0, path_1.join)(__dirname, "../templates/", "componentImportConfig.json");
const configFile = (0, fs_1.readFileSync)(configPath, "utf-8");
return JSON.parse(configFile);
}
catch (error) {
console.error("Error loading component import configuration:", error);
return {};
}
};
exports.loadComponentConfig = loadComponentConfig;
/**
* Gets all files inside a specified folder with their content
* @param folderName The name of the folder to scan
* @param componentType The type of component (page, component, route, etc.)
* @param projectType The type of project (frontend, backend, blockchain)
* @returns Promise<TemplateFileInfo[]> Array of file info objects
* @throws Error when folder cannot be accessed or read
*/
function getFilesInFolder(folderName, componentType, projectType) {
return __awaiter(this, void 0, void 0, function* () {
// Get the base path for the component type
const basePath = yield getDefaultFolderForComponentType(projectType, componentType);
const fullPath = path_1.default.join(process.cwd(), basePath, folderName);
try {
// Verify the directory exists
yield fs_1.promises.access(fullPath);
}
catch (error) {
throw new Error(`Folder "${fullPath}" does not exist or cannot be accessed`);
}
try {
// Read all files in the directory
const files = yield fs_1.promises.readdir(fullPath);
// Process each file
const fileInfos = files.map((file) => __awaiter(this, void 0, void 0, function* () {
const filePath = path_1.default.join(fullPath, file);
const stats = yield fs_1.promises.stat(filePath);
if (stats.isFile()) {
const content = yield fs_1.promises.readFile(filePath, 'utf-8');
return {
originalFileName: file,
targetFileName: file, // Keeping same name unless you want to modify
content: content
};
}
// For directories, we could return null and filter them out
return {
originalFileName: file,
targetFileName: file,
content: undefined // or you might want to skip directories entirely
};
}));
// Wait for all files to be processed and filter out directories if needed
const results = yield Promise.all(fileInfos);
return results.filter(file => file.content !== undefined);
}
catch (error) {
throw new Error(`Failed to read files in folder "${fullPath}": ${error instanceof Error ? error.message : String(error)}`);
}
});
}