skaya
Version:
CLI SDK for full-stack automation: scaffold frontend, backend & blockchain. Future-ready for Web3, integrations, server components & logging.
176 lines (172 loc) • 7.83 kB
JavaScript
;
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.generateCodeWithAI = generateCodeWithAI;
const openai_1 = __importDefault(require("openai"));
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const enums_1 = require("../../bin/types/enums");
const config_1 = require("../config");
function generateCodeWithAI(fileName_1, projectType_1, componentType_1) {
return __awaiter(this, arguments, void 0, function* (fileName, projectType, componentType, aiDescription = '', options = {
style: 'css',
typescript: true,
withProps: true,
withState: false,
withEffects: false,
withTests: true,
withStories: projectType === enums_1.ProjectType.FRONTEND
}, templateFiles = [], extraOptions = {}) {
const apiKey = (0, config_1.getApiKey)();
if (!apiKey)
throw new Error(`${apiKey} API key is required.`);
const openai = new openai_1.default({ apiKey });
const updatedFiles = [];
const baseConfig = Object.assign({ componentName: fileName, aiDescription,
projectType,
componentType }, options);
for (const fileTemplate of templateFiles) {
const templateDir = path_1.default.join(__dirname, '..', 'templates', projectType.toLowerCase(), componentType);
const sourcePath = path_1.default.join(templateDir, fileTemplate.originalFileName);
if (!(0, fs_1.existsSync)(sourcePath)) {
throw new Error(`Template file not found: ${sourcePath}`);
}
const originalContent = (0, fs_1.readFileSync)(sourcePath, 'utf-8'); // Now reading the file, not the directory
const fileType = path_1.default.extname(fileTemplate.originalFileName).replace('.', '');
const systemPrompt = getSystemPrompt(fileType, componentType);
const userPrompt = buildFilePrompt(originalContent, baseConfig, fileTemplate.originalFileName);
const aiUpdatedContent = yield generateWithAI(openai, systemPrompt, userPrompt);
updatedFiles.push(Object.assign(Object.assign({}, fileTemplate), { content: aiUpdatedContent }));
}
return updatedFiles;
});
}
function generateWithAI(openai, systemPrompt, userPrompt) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
try {
const response = yield openai.chat.completions.create({
model: 'gpt-4',
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
temperature: 0.3,
max_tokens: 2000
});
return ((_c = (_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c.trim()) || '';
}
catch (error) {
console.error('Error generating file with AI:', error);
return '';
}
});
}
function getSystemPrompt(fileType, componentType) {
const basePrompt = `You are an expert full-stack developer. Generate clean, production-ready code that:
- Follows best practices for the specific file type
- Includes proper TypeScript types
- Has clear, concise comments where needed
- Is fully functional
- Matches modern architectural patterns
- Uses appropriate error handling
- Follows security best practices`;
// Handle file extensions first
switch (fileType) {
case 'tsx':
return componentType === enums_1.FrontendComponentType.PAGE
? `${basePrompt} for React page components. Include:
- Proper page-level structure
- SEO considerations if applicable
- Data fetching methods if needed
- Layout integration`
: `${basePrompt} for React components. Include:
- Proper component structure
- TypeScript interfaces
- Clean JSX
- Accessibility best practices`;
case 'test.tsx':
return `${basePrompt} for React component tests. Include:
- Testing Library best practices
- Meaningful test cases
- Proper mocking where needed
- Accessibility tests`;
case 'stories.tsx':
return `${basePrompt} for Storybook stories. Include:
- Comprehensive controls
- Multiple interaction states
- Documentation`;
case 'css':
case 'scss':
return `${basePrompt} for styles. Include:
- Modular CSS patterns
- Responsive design considerations
- BEM naming if appropriate
- Variables for theming`;
case 'test.ts':
return `${basePrompt} for backend tests. Include:
- Unit tests for business logic
- Integration tests for APIs
- Proper test setup/teardown
- Mocking of external services`;
case 'ts':
// Handle backend-specific component types
if (componentType) {
switch (componentType) {
case enums_1.BackendComponentType.ROUTE:
return `${basePrompt} for API routes. Include:
- RESTful design principles
- Proper HTTP status codes
- Input validation
- Error handling
- Documentation`;
case enums_1.BackendComponentType.CONTROLLER:
return `${basePrompt} for backend controllers. Include:
- Business logic encapsulation
- Clean separation of concerns
- Proper error handling
- Type-safe inputs/outputs
- Dependency injection`;
default:
return `${basePrompt} for general TypeScript files`;
}
}
return `${basePrompt} for general TypeScript files`;
default:
return basePrompt;
}
}
function buildFilePrompt(originalFileContent, config, originalFileName) {
return `
Update the following file based on the configuration below:
Configuration:
- Component Name: ${config.componentName}
- Component Type: ${config.componentType}
- Description: ${config.description}
- Project Type: ${config.projectType}
- Style: ${config.style}
- TypeScript: ${config.typescript}
- With Props: ${config.withProps}
- With State: ${config.withState}
- With Effects: ${config.withEffects}
- With Tests: ${config.withTests}
- With Stories: ${config.withStories}
- Original File Name: ${originalFileName}
File Content:
\`\`\`
${originalFileContent}
\`\`\`
Return only the updated file content. Do not include explanation or markdown syntax.
`;
}