Skip to content

Commit 56d5b58

Browse files
committed
feat: add middleware preset options to CLI and project form for enhanced application template customization
1 parent 480102d commit 56d5b58

2 files changed

Lines changed: 113 additions & 4 deletions

File tree

src/new/cli.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ const packageManagers: Array<string> = [
1313
...(process.platform !== "win32" ? ["bun"] : []),
1414
];
1515

16+
const middlewarePresets: Array<string> = [
17+
"api",
18+
"web",
19+
"graphql",
20+
"microservice",
21+
"minimal",
22+
];
23+
1624
const commandOptions = (yargs: Argv): Argv => {
1725
return yargs
1826
.positional("project-name", {
@@ -31,13 +39,20 @@ const commandOptions = (yargs: Argv): Argv => {
3139
choices: packageManagers,
3240
alias: "p",
3341
})
42+
.option("preset", {
43+
describe: "Middleware preset for Application template",
44+
type: "string",
45+
choices: middlewarePresets,
46+
alias: "s",
47+
})
3448
.option("directory", {
3549
describe: "The directory for new project",
3650
type: "string",
3751
alias: "d",
3852
})
3953
.implies("package-manager", "template")
40-
.implies("template", "package-manager");
54+
.implies("template", "package-manager")
55+
.implies("preset", "template");
4156
};
4257

4358
const checkNodeVersion = (): void => {
@@ -61,12 +76,14 @@ const createProject = (): CommandModule<CommandModuleArgs, any> => {
6176
packageManager,
6277
template,
6378
directory,
79+
preset,
6480
}) => {
6581
checkNodeVersion();
6682
return await projectForm(projectName, [
6783
packageManager,
6884
template,
6985
directory,
86+
preset,
7087
]);
7188
},
7289
};

src/new/form.ts

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,25 @@ const enum PackageManager {
180180
bun = "bun",
181181
}
182182

183+
/**
184+
* Middleware presets for Application template
185+
*/
186+
enum MiddlewarePreset {
187+
api = "API :: REST API with security, compression, and auto-logging. (Recommended)",
188+
web = "Web :: Full web app with cookies and session support.",
189+
graphql = "GraphQL :: Optimized for GraphQL APIs.",
190+
microservice = "Microservice :: Minimal setup for microservices.",
191+
minimal = "Minimal :: Just request parsing, customize everything yourself.",
192+
}
193+
183194
type TemplateKeys = keyof typeof Template;
184-
type ProjectFormArgs = [PackageManager, TemplateKeys, string];
195+
type MiddlewarePresetKeys = keyof typeof MiddlewarePreset;
196+
type ProjectFormArgs = [
197+
PackageManager,
198+
TemplateKeys,
199+
string,
200+
MiddlewarePresetKeys,
201+
];
185202

186203
/**
187204
* Template folder mapping
@@ -191,6 +208,44 @@ const TEMPLATE_FOLDERS: Record<string, string> = {
191208
Micro: "micro",
192209
};
193210

211+
/**
212+
* Middleware preset mapping to code
213+
*/
214+
const PRESET_CODE: Record<string, string> = {
215+
API: `this.Middleware.applyPreset("api");`,
216+
Web: `this.Middleware.applyPreset("web");`,
217+
GraphQL: `this.Middleware.applyPreset("graphql");`,
218+
Microservice: `this.Middleware.applyPreset("microservice");`,
219+
Minimal: `this.Middleware.parse();`,
220+
};
221+
222+
/**
223+
* Apply the selected middleware preset to the generated app.ts
224+
*/
225+
function applyMiddlewarePreset(directory: string, preset: string): void {
226+
const appTsPath = path.join(directory, "src", "app.ts");
227+
228+
if (!fs.existsSync(appTsPath)) {
229+
return;
230+
}
231+
232+
// Extract preset name from selection (e.g., "API :: ..." -> "API")
233+
const presetMatch = preset.match(/^(\w+) ::/);
234+
const presetName = presetMatch ? presetMatch[1] : "API";
235+
236+
const presetCode = PRESET_CODE[presetName] || PRESET_CODE["API"];
237+
238+
let content = fs.readFileSync(appTsPath, "utf-8");
239+
240+
// Replace the placeholder with the preset code
241+
content = content.replace(
242+
/\/\/ __MIDDLEWARE_PRESET_PLACEHOLDER__/,
243+
presetCode,
244+
);
245+
246+
fs.writeFileSync(appTsPath, content, "utf-8");
247+
}
248+
194249
/**
195250
* Enable local template mode for testing
196251
* Set to true to use local templates instead of GitHub
@@ -221,20 +276,22 @@ const projectForm = async (
221276
name: string;
222277
packageManager: string;
223278
template: Template;
279+
preset?: MiddlewarePreset;
224280
confirm: boolean;
225281
};
226282

227-
const [packageManager, template, directory] = args;
283+
const [packageManager, template, directory, preset] = args;
228284

229285
if (packageManager && template) {
230286
answer = {
231287
name: projectName,
232288
packageManager: packageManager,
233289
template: Template[template],
290+
preset: preset ? MiddlewarePreset[preset] : undefined,
234291
confirm: true,
235292
};
236293
} else {
237-
answer = await inquirer.prompt([
294+
const baseAnswers = await inquirer.prompt([
238295
{
239296
type: "input",
240297
name: "name",
@@ -266,13 +323,43 @@ const projectForm = async (
266323
"Micro :: A minimalistic template for building micro APIs and serverless functions.",
267324
],
268325
},
326+
]);
327+
328+
// Only show preset selection for Application template
329+
let presetAnswer: { preset?: MiddlewarePreset } = {};
330+
if (baseAnswers.template.startsWith("Application")) {
331+
presetAnswer = await inquirer.prompt([
332+
{
333+
type: "list",
334+
name: "preset",
335+
message: "Select a middleware preset",
336+
choices: [
337+
`API :: REST API with security, compression, and auto-logging. (${chalk.yellow(
338+
"Recommended",
339+
)})`,
340+
"Web :: Full web app with cookies and session support.",
341+
"GraphQL :: Optimized for GraphQL APIs.",
342+
"Microservice :: Minimal setup for microservices.",
343+
"Minimal :: Just request parsing, customize everything yourself.",
344+
],
345+
},
346+
]);
347+
}
348+
349+
const confirmAnswer = await inquirer.prompt([
269350
{
270351
type: "confirm",
271352
name: "confirm",
272353
message: "Do you want to create this project?",
273354
default: true,
274355
},
275356
]);
357+
358+
answer = {
359+
...baseAnswers,
360+
...presetAnswer,
361+
...confirmAnswer,
362+
};
276363
}
277364

278365
if (directory) {
@@ -380,6 +467,11 @@ const projectForm = async (
380467
progressBar.update(90, { doing: "Finalizing project" });
381468
}
382469

470+
// Apply middleware preset for Application template
471+
if (answer.preset && templateFolder === "application") {
472+
applyMiddlewarePreset(answer.name, answer.preset);
473+
}
474+
383475
changePackageName({
384476
directory: answer.name,
385477
name: projectName,

0 commit comments

Comments
 (0)