11import { NextRequest , NextResponse } from 'next/server'
22import { readFile } from 'fs/promises'
33import path from 'path'
4+
45import type { WizardResponses } from '@/types/wizard'
56import { getTemplateConfig , type TemplateKey } from '@/lib/template-config'
67
7- // Helper function to map output file types to template types
88function mapOutputFileToTemplateType ( outputFile : string ) : string {
99 const mapping : Record < string , string > = {
1010 'instructions-md' : 'copilot-instructions' ,
11+ 'agents-md' : 'agents' ,
1112 'cursor-rules' : 'cursor-rules' ,
1213 'json-rules' : 'json-rules' ,
13- 'agents-md' : 'agents'
1414 }
15- return mapping [ outputFile ] || outputFile
15+
16+ return mapping [ outputFile ] ?? outputFile
1617}
1718
1819export async function POST (
1920 request : NextRequest ,
20- { params } : { params : { ide : string ; framework : string ; fileName : string } }
21+ { params } : { params : { framework : string ; fileName : string } } ,
2122) {
2223 try {
23- const { ide, framework, fileName } = params
24- const body = await request . json ( )
25- const responses : WizardResponses = body
26-
27- // Determine template configuration based on the request
28- let templateConfig
29-
30- const frameworkFromPath = framework && ! [ 'general' , 'none' , 'undefined' ] . includes ( framework )
31- ? framework
32- : undefined
33-
34- if ( ide ) {
35- const templateKeyFromParams : TemplateKey = {
36- ide,
37- templateType : mapOutputFileToTemplateType ( fileName ) ,
38- framework : frameworkFromPath
39- }
40- templateConfig = getTemplateConfig ( templateKeyFromParams )
24+ const { framework, fileName } = params
25+ const responses = ( await request . json ( ) ) as WizardResponses
26+
27+ const frameworkFromPath =
28+ framework && ! [ 'general' , 'none' , 'undefined' ] . includes ( framework )
29+ ? framework
30+ : undefined
31+
32+ const templateKeyFromParams : TemplateKey = {
33+ templateType : mapOutputFileToTemplateType ( fileName ) ,
34+ framework : frameworkFromPath ,
4135 }
4236
43- // Check if this is a combination-based request
44- if ( ! templateConfig && responses . preferredIde && responses . outputFile ) {
45- const templateKey : TemplateKey = {
46- ide : responses . preferredIde ,
37+ let templateConfig = getTemplateConfig ( templateKeyFromParams )
38+
39+ if ( ! templateConfig && responses . outputFile ) {
40+ const templateKeyFromBody : TemplateKey = {
4741 templateType : mapOutputFileToTemplateType ( responses . outputFile ) ,
48- framework : responses . frameworkSelection || undefined
42+ framework : responses . frameworkSelection || undefined ,
4943 }
50- templateConfig = getTemplateConfig ( templateKey )
44+
45+ templateConfig = getTemplateConfig ( templateKeyFromBody )
5146 }
5247
53- // Fallback to legacy fileName-based approach
5448 if ( ! templateConfig ) {
5549 templateConfig = getTemplateConfig ( fileName )
5650 }
5751
5852 if ( ! templateConfig ) {
5953 return NextResponse . json (
6054 { error : `Template not found for fileName: ${ fileName } ` } ,
61- { status : 404 }
55+ { status : 404 } ,
6256 )
6357 }
6458
65- // Read the template file
6659 const templatePath = path . join ( process . cwd ( ) , 'file-templates' , templateConfig . template )
6760 const template = await readFile ( templatePath , 'utf-8' )
6861
69- // Replace template variables with actual values
7062 let generatedContent = template
63+ const isJsonTemplate = templateConfig . template . toLowerCase ( ) . endsWith ( '.json' )
7164
72- // Helper function to replace template variables gracefully
73- const replaceVariable = ( key : keyof WizardResponses , fallback : string = 'Not specified' ) => {
74- const value = responses [ key ]
65+ const escapeForJson = ( value : string ) => {
66+ const escaped = JSON . stringify ( value )
67+ return escaped . slice ( 1 , - 1 )
68+ }
69+
70+ const replaceVariable = ( key : keyof WizardResponses , fallback = 'Not specified' ) => {
7571 const placeholder = `{{${ key } }}`
7672
73+ if ( ! generatedContent . includes ( placeholder ) ) {
74+ return
75+ }
76+
77+ const value = responses [ key ]
78+
7779 if ( value === null || value === undefined || value === '' ) {
78- generatedContent = generatedContent . replace ( placeholder , fallback )
80+ const replacement = isJsonTemplate ? escapeForJson ( fallback ) : fallback
81+ generatedContent = generatedContent . replace ( placeholder , replacement )
7982 } else {
80- generatedContent = generatedContent . replace ( placeholder , String ( value ) )
83+ const replacementValue = String ( value )
84+ const replacement = isJsonTemplate ? escapeForJson ( replacementValue ) : replacementValue
85+ generatedContent = generatedContent . replace ( placeholder , replacement )
8186 }
8287 }
8388
84- // Replace all template variables
85- replaceVariable ( 'preferredIde' )
8689 replaceVariable ( 'frameworkSelection' )
8790 replaceVariable ( 'tooling' )
8891 replaceVariable ( 'language' )
@@ -108,18 +111,14 @@ export async function POST(
108111 replaceVariable ( 'logging' )
109112 replaceVariable ( 'commitStyle' )
110113 replaceVariable ( 'prRules' )
114+ replaceVariable ( 'outputFile' )
111115
112- // Return the generated content
113116 return NextResponse . json ( {
114117 content : generatedContent ,
115- fileName : templateConfig . outputFileName
118+ fileName : templateConfig . outputFileName ,
116119 } )
117-
118120 } catch ( error ) {
119121 console . error ( 'Error generating file:' , error )
120- return NextResponse . json (
121- { error : 'Failed to generate file' } ,
122- { status : 500 }
123- )
122+ return NextResponse . json ( { error : 'Failed to generate file' } , { status : 500 } )
124123 }
125124}
0 commit comments