create-next-pro-cli
Version:
Advanced Next.js project scaffolder with i18n, Tailwind, App Router and more.
171 lines (160 loc) • 5.41 kB
text/typescript
import { join } from "node:path";
import { mkdir, readFile, writeFile, readdir } from "node:fs/promises";
import prompts from "prompts";
import { capitalize, toFileName } from "./utils"; // Assuming you have a utility function to capitalize strings
import { existsSync } from "node:fs";
export async function addPage(args: string[]) {
let pageName = args[1];
if (!pageName || pageName.startsWith("-")) {
const response = await prompts.prompt({
type: "text",
name: "pageName",
message: "📝 Page name to add:",
validate: (name: string) => (name ? true : "Page name is required"),
});
pageName = response.pageName;
}
// Handle nested pages
let parentName = null;
let childName = null;
if (pageName.includes(".")) {
[parentName, childName] = pageName.split(".");
}
let shortFlags = args.find((arg) => /^-[A-Za-z]+$/.test(arg));
let longFlags = new Set(args.filter((a) => a.startsWith("--")));
const flags = new Set<string>();
if (!shortFlags && Array.from(longFlags).length === 0) {
shortFlags = "-LPl";
}
if (shortFlags) {
for (const char of shortFlags.slice(1)) {
switch (char) {
case "L":
flags.add("layout");
break;
case "P":
flags.add("page");
break;
case "l":
flags.add("loading");
break;
case "n":
flags.add("not-found");
break;
case "e":
flags.add("error");
break;
case "g":
flags.add("global-error");
break;
case "r":
flags.add("route");
break;
case "t":
flags.add("template");
break;
case "d":
flags.add("default");
break;
}
}
}
for (const flag of [
"layout",
"page",
"loading",
"not-found",
"error",
"global-error",
"route",
"template",
"default",
]) {
if (longFlags.has("--" + flag)) flags.add(flag);
}
const srcPath = join(process.cwd(), "src", "app", "[locale]");
const messagesPath = join(process.cwd(), "messages");
const templatePath = join(import.meta.dir, "..", "..", "templates", "Page");
const entries = await readdir(messagesPath, { withFileTypes: true });
const locales = entries.filter((e) => e.isDirectory()).map((e) => e.name);
// Create folders/files for nested or simple page
let uiPageDir, localePagePath, jsonFileName;
if (parentName && childName) {
uiPageDir = join(process.cwd(), "src", "ui", parentName, childName);
localePagePath = join(srcPath, parentName, childName);
jsonFileName = parentName;
} else {
uiPageDir = join(process.cwd(), "src", "ui", pageName);
localePagePath = join(srcPath, pageName);
jsonFileName = pageName;
}
if (!existsSync(uiPageDir)) {
await mkdir(uiPageDir, { recursive: true });
}
const uiPageFile = join(uiPageDir, "page-ui.tsx");
const uiPageTemplate = join(templatePath, "page-ui.tsx");
if (existsSync(uiPageTemplate)) {
let uiContent = await readFile(uiPageTemplate, "utf-8");
uiContent = uiContent
.replace(/template/g, childName || pageName)
.replace(/Template/g, capitalize(childName || pageName));
await writeFile(uiPageFile, uiContent);
console.log(`📄 File created: ${uiPageFile}`);
} else {
console.warn("⚠️ Template page-ui.tsx manquant.");
}
if (!existsSync(localePagePath)) {
await mkdir(localePagePath, { recursive: true });
}
for (const flag of flags) {
const filename = toFileName(flag);
const src = join(templatePath, filename);
const dst = join(localePagePath, filename);
if (!existsSync(src)) {
console.warn(`⚠️ Missing template file: ${filename}`);
continue;
}
const content = await readFile(src, "utf-8");
const replaced = content
.replace(/template/g, childName || pageName)
.replace(/Template/g, capitalize(childName || pageName));
await writeFile(dst, replaced);
console.log(`📄 File created: ${dst}`);
}
// Add JSON to parent object if nested, otherwise create a simple file
const jsonTemplate = join(templatePath, "page.json");
if (!existsSync(jsonTemplate)) {
console.warn("⚠️ Missing template page.json.");
}
const content = await readFile(jsonTemplate, "utf-8");
const replaced = content
.replace(/template/g, childName || pageName)
.replace(/Template/g, capitalize(childName || pageName));
for (const locale of locales) {
// Only process if messages/<locale> is a directory
const localeDir = join(messagesPath, locale);
if (
!existsSync(localeDir) ||
!require("node:fs").statSync(localeDir).isDirectory()
)
continue;
const jsonTarget = join(messagesPath, locale, `${jsonFileName}.json`);
let current: Record<string, any> = {};
if (existsSync(jsonTarget)) {
const jsonFile = await readFile(jsonTarget, "utf-8");
try {
current = JSON.parse(jsonFile) as Record<string, any>;
} catch {
current = {};
}
}
if (parentName && childName) {
current[childName] = JSON.parse(replaced);
} else {
// fichier simple
current = JSON.parse(replaced);
}
await writeFile(jsonTarget, JSON.stringify(current, null, 2));
}
console.log(`✅ Page "${pageName}" with templates added for each locale.`);
}