import { exec } from 'child_process';
import { promisify } from 'util';
import fs from 'fs-extra';
import path from 'path';
const execAsync = promisify(exec);
export const webDevTools = new Map([
[
'create_component',
{
name: 'create_component',
description: 'Create frontend component (React, Vue, Angular)',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Component name' },
framework: {
type: 'string',
enum: ['react', 'vue', 'angular', 'svelte'],
description: 'Frontend framework'
},
type: {
type: 'string',
enum: ['functional', 'class', 'page', 'layout', 'hook', 'service'],
description: 'Component type'
},
props: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string' },
required: { type: 'boolean', default: false },
default: { type: 'string' }
}
},
description: 'Component props/properties'
},
projectPath: { type: 'string', description: 'Project path' },
withTests: { type: 'boolean', default: true },
withStories: { type: 'boolean', default: false },
styling: {
type: 'string',
enum: ['css', 'scss', 'styled-components', 'tailwind', 'module'],
default: 'css'
}
},
required: ['name', 'framework', 'projectPath']
},
async execute(args: any) {
const { name, framework, type = 'functional', props = [], projectPath, withTests = true, withStories = false, styling = 'css' } = args;
switch (framework) {
case 'react':
return await createReactComponent(name, type, props, projectPath, withTests, withStories, styling);
case 'vue':
return await createVueComponent(name, props, projectPath, withTests, styling);
case 'angular':
return await createAngularComponent(name, props, projectPath, withTests);
case 'svelte':
return await createSvelteComponent(name, props, projectPath, withTests, styling);
default:
throw new Error(`Unsupported framework: ${framework}`);
}
}
}
],
[
'setup_styling',
{
name: 'setup_styling',
description: 'Setup CSS framework or styling solution',
inputSchema: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['tailwind', 'bootstrap', 'material-ui', 'chakra-ui', 'ant-design', 'styled-components', 'emotion', 'sass'],
description: 'Styling solution'
},
projectPath: { type: 'string', description: 'Project path' },
framework: { type: 'string', enum: ['react', 'vue', 'angular'], description: 'Frontend framework' }
},
required: ['type', 'projectPath', 'framework']
},
async execute(args: any) {
const { type, projectPath, framework } = args;
switch (type) {
case 'tailwind':
return await setupTailwind(projectPath, framework);
case 'bootstrap':
return await setupBootstrap(projectPath, framework);
case 'material-ui':
return await setupMaterialUI(projectPath);
case 'styled-components':
return await setupStyledComponents(projectPath);
default:
throw new Error(`Unsupported styling solution: ${type}`);
}
}
}
],
[
'create_page',
{
name: 'create_page',
description: 'Create page/route with routing setup',
inputSchema: {
type: 'object',
properties: {
name: { type: 'string', description: 'Page name' },
path: { type: 'string', description: 'Route path' },
framework: { type: 'string', enum: ['react', 'vue', 'angular', 'nextjs', 'nuxtjs'] },
projectPath: { type: 'string', description: 'Project path' },
components: {
type: 'array',
items: { type: 'string' },
description: 'Components to include in page'
},
layout: { type: 'string', description: 'Layout to use' },
metadata: {
type: 'object',
properties: {
title: { type: 'string' },
description: { type: 'string' },
keywords: { type: 'array', items: { type: 'string' } }
}
}
},
required: ['name', 'path', 'framework', 'projectPath']
},
async execute(args: any) {
const { name, path: routePath, framework, projectPath, components = [], layout, metadata } = args;
switch (framework) {
case 'react':
return await createReactPage(name, routePath, projectPath, components, layout, metadata);
case 'nextjs':
return await createNextJSPage(name, routePath, projectPath, components, metadata);
case 'vue':
return await createVuePage(name, routePath, projectPath, components, layout, metadata);
case 'nuxtjs':
return await createNuxtPage(name, routePath, projectPath, components, metadata);
case 'angular':
return await createAngularPage(name, routePath, projectPath, components);
default:
throw new Error(`Unsupported framework: ${framework}`);
}
}
}
],
[
'setup_routing',
{
name: 'setup_routing',
description: 'Setup routing configuration',
inputSchema: {
type: 'object',
properties: {
framework: { type: 'string', enum: ['react', 'vue', 'angular'] },
projectPath: { type: 'string', description: 'Project path' },
router: {
type: 'string',
enum: ['react-router', 'vue-router', 'angular-router'],
description: 'Router library to use'
},
routes: {
type: 'array',
items: {
type: 'object',
properties: {
path: { type: 'string' },
component: { type: 'string' },
name: { type: 'string' },
guards: { type: 'array', items: { type: 'string' } }
}
},
description: 'Initial routes to setup'
}
},
required: ['framework', 'projectPath']
},
async execute(args: any) {
const { framework, projectPath, router, routes = [] } = args;
switch (framework) {
case 'react':
return await setupReactRouter(projectPath, routes);
case 'vue':
return await setupVueRouter(projectPath, routes);
case 'angular':
return await setupAngularRouter(projectPath, routes);
default:
throw new Error(`Unsupported framework: ${framework}`);
}
}
}
],
[
'setup_state_management',
{
name: 'setup_state_management',
description: 'Setup state management solution',
inputSchema: {
type: 'object',
properties: {
type: {
type: 'string',
enum: ['redux', 'zustand', 'jotai', 'recoil', 'vuex', 'pinia', 'ngrx'],
description: 'State management solution'
},
framework: { type: 'string', enum: ['react', 'vue', 'angular'] },
projectPath: { type: 'string', description: 'Project path' },
stores: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
state: { type: 'object' },
actions: { type: 'array', items: { type: 'string' } }
}
},
description: 'Initial stores to create'
}
},
required: ['type', 'framework', 'projectPath']
},
async execute(args: any) {
const { type, framework, projectPath, stores = [] } = args;
switch (type) {
case 'redux':
return await setupRedux(projectPath, stores);
case 'zustand':
return await setupZustand(projectPath, stores);
case 'vuex':
return await setupVuex(projectPath, stores);
case 'pinia':
return await setupPinia(projectPath, stores);
case 'ngrx':
return await setupNgRx(projectPath, stores);
default:
throw new Error(`Unsupported state management: ${type}`);
}
}
}
],
[
'setup_forms',
{
name: 'setup_forms',
description: 'Setup form handling and validation',
inputSchema: {
type: 'object',
properties: {
framework: { type: 'string', enum: ['react', 'vue', 'angular'] },
library: {
type: 'string',
enum: ['react-hook-form', 'formik', 'vee-validate', 'reactive-forms'],
description: 'Form library to use'
},
validation: {
type: 'string',
enum: ['yup', 'joi', 'zod', 'class-validator'],
description: 'Validation library'
},
projectPath: { type: 'string', description: 'Project path' },
forms: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
fields: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string' },
type: { type: 'string' },
validation: { type: 'object' }
}
}
}
}
},
description: 'Forms to create'
}
},
required: ['framework', 'projectPath']
},
async execute(args: any) {
const { framework, library, validation, projectPath, forms = [] } = args;
switch (framework) {
case 'react':
return await setupReactForms(projectPath, library, validation, forms);
case 'vue':
return await setupVueForms(projectPath, library, validation, forms);
case 'angular':
return await setupAngularForms(projectPath, validation, forms);
default:
throw new Error(`Unsupported framework: ${framework}`);
}
}
}
],
[
'optimize_bundle',
{
name: 'optimize_bundle',
description: 'Optimize webpack/vite bundle configuration',
inputSchema: {
type: 'object',
properties: {
bundler: { type: 'string', enum: ['webpack', 'vite', 'parcel', 'rollup'] },
projectPath: { type: 'string', description: 'Project path' },
optimizations: {
type: 'array',
items: {
type: 'string',
enum: ['code-splitting', 'tree-shaking', 'compression', 'lazy-loading', 'preloading', 'caching']
},
description: 'Optimizations to apply'
},
target: { type: 'string', enum: ['development', 'production'], default: 'production' }
},
required: ['bundler', 'projectPath']
},
async execute(args: any) {
const { bundler, projectPath, optimizations = [], target = 'production' } = args;
switch (bundler) {
case 'webpack':
return await optimizeWebpack(projectPath, optimizations, target);
case 'vite':
return await optimizeVite(projectPath, optimizations, target);
default:
throw new Error(`Unsupported bundler: ${bundler}`);
}
}
}
]
]);
async function createReactComponent(name: string, type: string, props: any[], projectPath: string, withTests: boolean, withStories: boolean, styling: string) {
const componentDir = path.join(projectPath, 'src/components', name);
await fs.ensureDir(componentDir);
// Generate props interface
let propsInterface = '';
if (props.length > 0) {
propsInterface = `interface ${name}Props {\n`;
for (const prop of props) {
propsInterface += ` ${prop.name}${prop.required ? '' : '?'}: ${prop.type};\n`;
}
propsInterface += '}\n\n';
}
// Generate component content
let componentContent = `import React from 'react';\n`;
if (styling === 'styled-components') {
componentContent += `import styled from 'styled-components';\n`;
} else if (styling !== 'tailwind') {
componentContent += `import './${name}.${styling === 'module' ? 'module.' : ''}css';\n`;
}
componentContent += `\n${propsInterface}`;
if (type === 'functional') {
componentContent += `const ${name}: React.FC${props.length > 0 ? `<${name}Props>` : ''} = (${props.length > 0 ? `{ ${props.map(p => p.name).join(', ')} }` : ''}) => {\n`;
componentContent += ` return (\n`;
componentContent += ` <div className="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}">\n`;
componentContent += ` <h2>Hello from ${name}!</h2>\n`;
if (props.length > 0) {
componentContent += ` <pre>{JSON.stringify({ ${props.map(p => p.name).join(', ')} }, null, 2)}</pre>\n`;
}
componentContent += ` </div>\n`;
componentContent += ` );\n`;
componentContent += `};\n\n`;
} else if (type === 'class') {
componentContent += `class ${name} extends React.Component${props.length > 0 ? `<${name}Props>` : ''} {\n`;
componentContent += ` render() {\n`;
componentContent += ` return (\n`;
componentContent += ` <div className="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}">\n`;
componentContent += ` <h2>Hello from ${name}!</h2>\n`;
if (props.length > 0) {
componentContent += ` <pre>{JSON.stringify(this.props, null, 2)}</pre>\n`;
}
componentContent += ` </div>\n`;
componentContent += ` );\n`;
componentContent += ` }\n`;
componentContent += `}\n\n`;
} else if (type === 'hook') {
componentContent = `import { useState, useEffect } from 'react';\n\n`;
componentContent += `export const use${name} = () => {\n`;
componentContent += ` const [data, setData] = useState(null);\n`;
componentContent += ` const [loading, setLoading] = useState(false);\n`;
componentContent += ` const [error, setError] = useState(null);\n\n`;
componentContent += ` useEffect(() => {\n`;
componentContent += ` // Hook logic here\n`;
componentContent += ` }, []);\n\n`;
componentContent += ` return { data, loading, error };\n`;
componentContent += `};\n\n`;
componentContent += `export default use${name};\n`;
}
if (type !== 'hook') {
componentContent += `export default ${name};\n`;
}
await fs.writeFile(path.join(componentDir, `${name}.tsx`), componentContent);
// Create styling file
if (styling !== 'tailwind' && styling !== 'styled-components' && type !== 'hook') {
const styleExt = styling === 'scss' ? 'scss' : 'css';
const isModule = styling === 'module';
const styleFileName = isModule ? `${name}.module.${styleExt}` : `${name}.${styleExt}`;
const styleContent = `.${name.toLowerCase()} {
padding: 1rem;
h2 {
color: #333;
margin-bottom: 1rem;
}
}`;
await fs.writeFile(path.join(componentDir, styleFileName), styleContent);
}
// Create test file
if (withTests && type !== 'hook') {
const testContent = `import React from 'react';
import { render, screen } from '@testing-library/react';
import ${name} from './${name}';
describe('${name}', () => {
it('renders without crashing', () => {
render(<${name} />);
expect(screen.getByText(/Hello from ${name}!/)).toBeInTheDocument();
});
});`;
await fs.writeFile(path.join(componentDir, `${name}.test.tsx`), testContent);
}
// Create Storybook story
if (withStories && type !== 'hook') {
const storyContent = `import type { Meta, StoryObj } from '@storybook/react';
import ${name} from './${name}';
const meta: Meta<typeof ${name}> = {
title: 'Components/${name}',
component: ${name},
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
${props.map(p => `${p.name}: ${p.default || `'sample ${p.name}'`}`).join(',\n ')}
},
};`;
await fs.writeFile(path.join(componentDir, `${name}.stories.tsx`), storyContent);
}
// Create index file
const indexContent = `export { default } from './${name}';${type === 'hook' ? `\nexport { use${name} } from './${name}';` : ''}`;
await fs.writeFile(path.join(componentDir, 'index.ts'), indexContent);
return `React component ${name} created successfully at ${componentDir}`;
}
async function createVueComponent(name: string, props: any[], projectPath: string, withTests: boolean, styling: string) {
const componentDir = path.join(projectPath, 'src/components');
await fs.ensureDir(componentDir);
let componentContent = `<template>
<div class="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}">
<h2>Hello from ${name}!</h2>
<pre v-if="Object.keys($props).length">{{ $props }}</pre>
</div>
</template>
<script setup lang="ts">
${props.length > 0 ? `interface Props {
${props.map(p => ` ${p.name}${p.required ? '' : '?'}: ${p.type};`).join('\n')}
}
defineProps<Props>();` : ''}
</script>
${styling !== 'tailwind' ? `<style scoped>
.${name.toLowerCase()} {
padding: 1rem;
}
.${name.toLowerCase()} h2 {
color: #333;
margin-bottom: 1rem;
}
</style>` : ''}`;
await fs.writeFile(path.join(componentDir, `${name}.vue`), componentContent);
if (withTests) {
const testContent = `import { describe, it, expect } from 'vitest';
import { mount } from '@vue/test-utils';
import ${name} from './${name}.vue';
describe('${name}', () => {
it('renders properly', () => {
const wrapper = mount(${name});
expect(wrapper.text()).toContain('Hello from ${name}!');
});
});`;
await fs.writeFile(path.join(componentDir, `${name}.spec.ts`), testContent);
}
return `Vue component ${name} created successfully`;
}
async function createAngularComponent(name: string, props: any[], projectPath: string, withTests: boolean) {
await execAsync(`cd "${projectPath}" && ng generate component ${name}`);
return `Angular component ${name} created successfully`;
}
async function createSvelteComponent(name: string, props: any[], projectPath: string, withTests: boolean, styling: string) {
const componentDir = path.join(projectPath, 'src/lib/components');
await fs.ensureDir(componentDir);
let componentContent = `<script lang="ts">
${props.map(p => ` export let ${p.name}: ${p.type}${p.default ? ` = ${p.default}` : ''};`).join('\n')}
</script>
<div class="${styling === 'tailwind' ? 'p-4' : name.toLowerCase()}">
<h2>Hello from ${name}!</h2>
${props.length > 0 ? `<pre>{JSON.stringify({ ${props.map(p => p.name).join(', ')} }, null, 2)}</pre>` : ''}
</div>
${styling !== 'tailwind' ? `<style>
.${name.toLowerCase()} {
padding: 1rem;
}
.${name.toLowerCase()} h2 {
color: #333;
margin-bottom: 1rem;
}
</style>` : ''}`;
await fs.writeFile(path.join(componentDir, `${name}.svelte`), componentContent);
return `Svelte component ${name} created successfully`;
}
async function setupTailwind(projectPath: string, framework: string) {
await execAsync(`cd "${projectPath}" && npm install -D tailwindcss postcss autoprefixer`);
await execAsync(`cd "${projectPath}" && npx tailwindcss init -p`);
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx,vue,svelte}",
],
theme: {
extend: {},
},
plugins: [],
}`;
await fs.writeFile(path.join(projectPath, 'tailwind.config.js'), tailwindConfig);
const cssPath = framework === 'vue' ? 'src/style.css' : 'src/index.css';
const cssContent = `@tailwind base;
@tailwind components;
@tailwind utilities;`;
await fs.writeFile(path.join(projectPath, cssPath), cssContent);
return 'Tailwind CSS setup completed';
}
async function setupBootstrap(projectPath: string, framework: string) {
await execAsync(`cd "${projectPath}" && npm install bootstrap`);
const importPath = framework === 'vue' ? 'src/main.ts' : 'src/index.tsx';
let mainContent = await fs.readFile(path.join(projectPath, importPath), 'utf-8');
mainContent = `import 'bootstrap/dist/css/bootstrap.min.css';\n${mainContent}`;
await fs.writeFile(path.join(projectPath, importPath), mainContent);
return 'Bootstrap setup completed';
}
async function setupMaterialUI(projectPath: string) {
await execAsync(`cd "${projectPath}" && npm install @mui/material @emotion/react @emotion/styled`);
return 'Material-UI setup completed';
}
async function setupStyledComponents(projectPath: string) {
await execAsync(`cd "${projectPath}" && npm install styled-components`);
await execAsync(`cd "${projectPath}" && npm install -D @types/styled-components`);
return 'Styled Components setup completed';
}
async function createReactPage(name: string, routePath: string, projectPath: string, components: string[], layout?: string, metadata?: any) {
const pagesDir = path.join(projectPath, 'src/pages');
await fs.ensureDir(pagesDir);
let pageContent = `import React from 'react';\n`;
if (layout) {
pageContent += `import ${layout} from '../layouts/${layout}';\n`;
}
for (const component of components) {
pageContent += `import ${component} from '../components/${component}';\n`;
}
pageContent += `\nconst ${name}Page: React.FC = () => {\n`;
pageContent += ` return (\n`;
if (layout) {
pageContent += ` <${layout}>\n`;
}
pageContent += ` <div className="page-${name.toLowerCase()}">\n`;
pageContent += ` <h1>${name} Page</h1>\n`;
for (const component of components) {
pageContent += ` <${component} />\n`;
}
pageContent += ` </div>\n`;
if (layout) {
pageContent += ` </${layout}>\n`;
}
pageContent += ` );\n`;
pageContent += `};\n\n`;
pageContent += `export default ${name}Page;\n`;
await fs.writeFile(path.join(pagesDir, `${name}.tsx`), pageContent);
return `React page ${name} created successfully`;
}
async function createNextJSPage(name: string, routePath: string, projectPath: string, components: string[], metadata?: any) {
const pagesDir = path.join(projectPath, 'pages');
await fs.ensureDir(pagesDir);
let pageContent = `import Head from 'next/head';\n`;
for (const component of components) {
pageContent += `import ${component} from '../components/${component}';\n`;
}
pageContent += `\nexport default function ${name}() {\n`;
pageContent += ` return (\n`;
pageContent += ` <>\n`;
if (metadata) {
pageContent += ` <Head>\n`;
if (metadata.title) pageContent += ` <title>${metadata.title}</title>\n`;
if (metadata.description) pageContent += ` <meta name="description" content="${metadata.description}" />\n`;
pageContent += ` </Head>\n`;
}
pageContent += ` <main>\n`;
pageContent += ` <h1>${name} Page</h1>\n`;
for (const component of components) {
pageContent += ` <${component} />\n`;
}
pageContent += ` </main>\n`;
pageContent += ` </>\n`;
pageContent += ` );\n`;
pageContent += `}\n`;
await fs.writeFile(path.join(pagesDir, `${routePath}.tsx`), pageContent);
return `Next.js page ${name} created successfully`;
}
async function createVuePage(name: string, routePath: string, projectPath: string, components: string[], layout?: string, metadata?: any) {
const pagesDir = path.join(projectPath, 'src/views');
await fs.ensureDir(pagesDir);
let pageContent = `<template>
<div class="page-${name.toLowerCase()}">
<h1>${name} Page</h1>
`;
for (const component of components) {
pageContent += ` <${component} />\n`;
}
pageContent += ` </div>
</template>
<script setup lang="ts">
`;
for (const component of components) {
pageContent += `import ${component} from '@/components/${component}.vue';\n`;
}
if (metadata) {
pageContent += `
import { useMeta } from '@unhead/vue';
useMeta({
title: '${metadata.title || name}',
meta: [
{ name: 'description', content: '${metadata.description || ''}' }
]
});`;
}
pageContent += `
</script>
<style scoped>
.page-${name.toLowerCase()} {
padding: 2rem;
}
</style>`;
await fs.writeFile(path.join(pagesDir, `${name}.vue`), pageContent);
return `Vue page ${name} created successfully`;
}
async function createNuxtPage(name: string, routePath: string, projectPath: string, components: string[], metadata?: any) {
const pagesDir = path.join(projectPath, 'pages');
await fs.ensureDir(pagesDir);
let pageContent = `<template>
<div>
<Head>
<Title>${metadata?.title || name}</Title>
<Meta name="description" :content="'${metadata?.description || ''}'" />
</Head>
<main>
<h1>${name} Page</h1>
`;
for (const component of components) {
pageContent += ` <${component} />\n`;
}
pageContent += ` </main>
</div>
</template>
<script setup lang="ts">
`;
for (const component of components) {
pageContent += `import ${component} from '~/components/${component}.vue';\n`;
}
pageContent += `</script>`;
await fs.writeFile(path.join(pagesDir, `${routePath}.vue`), pageContent);
return `Nuxt page ${name} created successfully`;
}
async function createAngularPage(name: string, routePath: string, projectPath: string, components: string[]) {
await execAsync(`cd "${projectPath}" && ng generate component pages/${name}`);
return `Angular page ${name} created successfully`;
}
async function setupReactRouter(projectPath: string, routes: any[]) {
await execAsync(`cd "${projectPath}" && npm install react-router-dom`);
await execAsync(`cd "${projectPath}" && npm install -D @types/react-router-dom`);
const routerContent = `import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
// Import your pages here
import Home from './pages/Home';
import About from './pages/About';
const AppRouter: React.FC = () => {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
${routes.map(route => `<Route path="${route.path}" element={<${route.component} />} />`).join('\n ')}
</Routes>
</Router>
);
};
export default AppRouter;`;
await fs.writeFile(path.join(projectPath, 'src/AppRouter.tsx'), routerContent);
return 'React Router setup completed';
}
async function setupVueRouter(projectPath: string, routes: any[]) {
await execAsync(`cd "${projectPath}" && npm install vue-router@4`);
const routerContent = `import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue')
},
${routes.map(route => `{
path: '${route.path}',
name: '${route.name}',
component: () => import('../views/${route.component}.vue')
}`).join(',\n ')}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;`;
await fs.ensureDir(path.join(projectPath, 'src/router'));
await fs.writeFile(path.join(projectPath, 'src/router/index.ts'), routerContent);
return 'Vue Router setup completed';
}
async function setupAngularRouter(projectPath: string, routes: any[]) {
// Angular CLI already sets up routing
return 'Angular Router already configured';
}
async function setupRedux(projectPath: string, stores: any[]) {
await execAsync(`cd "${projectPath}" && npm install @reduxjs/toolkit react-redux`);
const storeContent = `import { configureStore } from '@reduxjs/toolkit';
export const store = configureStore({
reducer: {
// Add your reducers here
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;`;
await fs.ensureDir(path.join(projectPath, 'src/store'));
await fs.writeFile(path.join(projectPath, 'src/store/index.ts'), storeContent);
return 'Redux Toolkit setup completed';
}
async function setupZustand(projectPath: string, stores: any[]) {
await execAsync(`cd "${projectPath}" && npm install zustand`);
for (const store of stores) {
const storeContent = `import { create } from 'zustand';
interface ${store.name}State {
${Object.keys(store.state || {}).map(key => `${key}: ${typeof store.state[key]};`).join('\n ')}
${store.actions?.map((action: string) => `${action}: () => void;`).join('\n ') || ''}
}
export const use${store.name}Store = create<${store.name}State>((set) => ({
${Object.entries(store.state || {}).map(([key, value]) => `${key}: ${JSON.stringify(value)},`).join('\n ')}
${store.actions?.map((action: string) => `${action}: () => set((state) => ({ ...state })),`).join('\n ') || ''}
}));`;
await fs.ensureDir(path.join(projectPath, 'src/stores'));
await fs.writeFile(path.join(projectPath, `src/stores/${store.name}.ts`), storeContent);
}
return 'Zustand stores setup completed';
}
async function setupVuex(projectPath: string, stores: any[]) {
await execAsync(`cd "${projectPath}" && npm install vuex@next`);
return 'Vuex setup completed';
}
async function setupPinia(projectPath: string, stores: any[]) {
await execAsync(`cd "${projectPath}" && npm install pinia`);
return 'Pinia setup completed';
}
async function setupNgRx(projectPath: string, stores: any[]) {
await execAsync(`cd "${projectPath}" && npm install @ngrx/store @ngrx/effects @ngrx/store-devtools`);
return 'NgRx setup completed';
}
async function setupReactForms(projectPath: string, library?: string, validation?: string, forms: any[] = []) {
if (library === 'react-hook-form') {
await execAsync(`cd "${projectPath}" && npm install react-hook-form`);
} else if (library === 'formik') {
await execAsync(`cd "${projectPath}" && npm install formik`);
}
if (validation === 'yup') {
await execAsync(`cd "${projectPath}" && npm install yup`);
} else if (validation === 'zod') {
await execAsync(`cd "${projectPath}" && npm install zod`);
}
return 'React forms setup completed';
}
async function setupVueForms(projectPath: string, library?: string, validation?: string, forms: any[] = []) {
if (library === 'vee-validate') {
await execAsync(`cd "${projectPath}" && npm install vee-validate`);
}
if (validation === 'yup') {
await execAsync(`cd "${projectPath}" && npm install yup`);
}
return 'Vue forms setup completed';
}
async function setupAngularForms(projectPath: string, validation?: string, forms: any[] = []) {
// Angular forms are built-in
return 'Angular forms already available';
}
async function optimizeWebpack(projectPath: string, optimizations: string[], target: string) {
const webpackConfigPath = path.join(projectPath, 'webpack.config.js');
const config = `const path = require('path');
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
mode: '${target}',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\\\/]node_modules[\\\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
usedExports: true,
sideEffects: false,
},
plugins: [
${optimizations.includes('compression') ? 'new CompressionPlugin(),' : ''}
],
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
};`;
await fs.writeFile(webpackConfigPath, config);
if (optimizations.includes('compression')) {
await execAsync(`cd "${projectPath}" && npm install -D compression-webpack-plugin`);
}
return 'Webpack optimization completed';
}
async function optimizeVite(projectPath: string, optimizations: string[], target: string) {
const viteConfigPath = path.join(projectPath, 'vite.config.ts');
let config = `import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
target: '${target}',
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
},
});`;
await fs.writeFile(viteConfigPath, config);
return 'Vite optimization completed';
}