This directory contains the configuration for mapping project features to their corresponding template files and directories.
The featureFileMap.ts file defines which files and directories should be included in generated projects based on the features selected by the user. This ensures that:
- Users only get the files they need based on selected features
- Preview and generated projects match exactly
- Optional dependencies and configurations aren't included unnecessarily
- Base Templates: Always included regardless of features (e.g.,
README.md,.gitignore) - Feature-Gated Templates: Only included when specific features are enabled (e.g.,
.env,Dockerfile) - Framework-Specific Gating: Some templates are gated per framework (e.g., FastAPI
auth/directory)
Maps feature names to common template files that apply across all frameworks:
{
env: [{ template: '.env.ejs', output: '.env' }],
docker: [
{ template: 'Dockerfile.ejs', output: 'Dockerfile' },
{ template: 'docker-compose.yml.ejs', output: 'docker-compose.yml' }
]
}Maps features to framework-specific templates and directories:
{
fastapi: {
auth: [{ directoryPattern: 'auth/' }],
testing: [{ directoryPattern: 'tests/' }]
},
django: {
rest_framework: [{ directoryPattern: 'apps/core/api/' }],
migrations: [{ directoryPattern: 'apps/core/migrations/' }]
},
flask: {
auth: [{ directoryPattern: 'app/auth/' }]
}
}The TemplateRenderer class uses these functions to determine which templates to render:
import { getCommonTemplates, shouldIncludeTemplate } from '../config/featureFileMap';
// Get list of common templates based on features
const templates = getCommonTemplates(framework, enabledFeatures);
// Check if a framework template should be included
if (shouldIncludeTemplate(templatePath, framework, enabledFeatures)) {
// Render template
}Generators use feature checks to conditionally create files:
// Only create .env if 'env' feature is enabled
if (config.features.includes('env')) {
const envFile = createEnvFile(config);
await fs.writeFile(path.join(projectDir, '.env'), envFile);
}To add a new optional file or directory:
-
Identify the scope: Is it common across frameworks or framework-specific?
-
Update the mapping:
For common files:
export const COMMON_FEATURE_FILES: Record<string, FeatureFileMapping[]> = { // ... existing mappings myFeature: [ { template: 'myfile.ejs', output: 'myfile.txt', frameworks: ['fastapi', 'django', 'flask'] } ] };
For framework-specific files:
export const FRAMEWORK_FEATURE_FILES = { fastapi: { // ... existing mappings myFeature: [ { directoryPattern: 'mydir/', frameworks: ['fastapi'] } ] } };
-
Update the feature definition in
client/src/lib/constants.ts:{ value: "myFeature", label: "My Feature", description: "Description of what this enables", supportedFrameworks: ["fastapi", "django", "flask"], default: false }
-
Test:
- Add test cases to
server/tests/preview.test.ts - Run
npm run test:preview - Perform manual QA using
server/tests/MANUAL_QA.md
- Add test cases to
Used when you want to gate specific template files:
{
template: 'source.ejs', // Template file in templates/common or templates/{framework}
output: 'destination.txt', // Output path in generated project
frameworks: ['fastapi'] // Optional: limit to specific frameworks
}Used when you want to gate entire directories:
{
directoryPattern: 'mydir/', // Directory path to match (all files in this dir)
frameworks: ['fastapi'] // Optional: limit to specific frameworks
}The shouldIncludeTemplate() function checks if a template path starts with any excluded directory pattern.
- Unit Tests: Test mapping functions directly
- Integration Tests: Test
/api/preview/structureendpoint with various feature combinations - Manual QA: Visual verification in UI that feature toggles work correctly
- Always specify frameworks: Even for "common" files, explicitly list supported frameworks
- Use directory patterns for related files: If a feature includes multiple files in a directory, use directory pattern
- Update tests when adding features: Keep test coverage comprehensive
- Document in CHANGELOG: Note any breaking changes to default feature sets
- Consider backwards compatibility: If changing default features, provide migration guide
- Check if the file is in
BASE_COMMON_TEMPLATES(always included) - Verify the feature is actually disabled in the config
- Check if the directory pattern is matching correctly
- Verify the feature is enabled in the config
- Check framework compatibility in the mapping
- Ensure template file exists in the templates directory
- Check for typos in template or output paths
- Verify both TemplateRenderer and generator code use the same feature checks
- For Django/Flask inline generators, ensure feature gates match the mapping config
- Check that
useProjectPreviewdependency array includes features