@teispace/next-maker 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,29 +1,29 @@
1
1
  #!/usr/bin/env node
2
- import{Command as xr}from"commander";import ae from"node:path";import G from"picocolors";import nt from"ora";function b(t="",e){let r=nt({text:t,...e});return r.start(),r}import st from"enquirer";var{prompt:at}=st,de=async t=>{let e=await at([{type:"input",name:"projectName",message:"What is the project name?",initial:t||"my-app",skip:!!t,validate:r=>/^[a-z0-9-_]+$/.test(r)?!0:"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:r=>/^\d+\.\d+\.\d+$/.test(r)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:r=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r)?!0:"Please enter a valid email address."},{type:"select",name:"packageManager",message:"Which package manager would you like to use?",choices:["npm","yarn","pnpm","bun"],initial:1},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",validate:r=>{if(!r)return!0;let o=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!o.test(r)&&!s.test(r)?"Please enter a valid GitHub repository URL (e.g., https://github.com/user/repo)":!0}},{type:"confirm",name:"keepTemplates",message:"Do you want to keep GitHub issue and pull request templates?",initial:!1},{type:"select",name:"httpClient",message:"Which HTTP client do you want to use?",choices:["axios","fetch","both","none"],initial:1},{type:"confirm",name:"reactSecureStorage",message:"Do you want to include react-secure-storage?",initial:!0,skip:function(){let r=this.state?.answers??this.enquirer?.answers??{};return!!(r.httpClient&&r.httpClient!=="none")}},{type:"confirm",name:"darkMode",message:"Do you want to include Dark Mode (Tailwind + next-themes)?",initial:!0},{type:"confirm",name:"redux",message:"Do you want to include Redux Toolkit?",initial:!0},{type:"confirm",name:"i18n",message:"Do you want to include Internationalization (next-intl)?",initial:!0},{type:"multiselect",name:"communityFiles",message:"Select community files to include:",choices:[{name:"CODE_OF_CONDUCT.md",value:"CODE_OF_CONDUCT.md"},{name:"CONTRIBUTING.md",value:"CONTRIBUTING.md"},{name:"SECURITY.md",value:"SECURITY.md"}],initial:[]},{type:"confirm",name:"readme",message:"Do you want to create a README.md?",initial:!0},{type:"confirm",name:"docker",message:"Do you want to include Docker configuration?",initial:!1},{type:"input",name:"containerName",message:"Docker Container Name:",initial:"next-app",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:r=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(r)?!0:"Invalid Docker container name."},{type:"input",name:"imageName",message:"Docker Image Name:",initial:"nextjs-starter",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:r=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(r)?!0:"Invalid Docker image name (must be lowercase)."},{type:"input",name:"imageTag",message:"Docker Image Tag:",initial:"latest",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:r=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(r)?!0:"Invalid Docker image tag."},{type:"confirm",name:"ci",message:"Do you want to include GitHub Actions (CI/CD)?",initial:!1},{type:"confirm",name:"preCommitHooks",message:"Do you want to setup pre-commit hooks (Husky, Commitlint, Lint-staged)?",initial:!0},{type:"confirm",name:"commitizen",message:"Do you want to setup Commitizen?",initial:!0},{type:"confirm",name:"copyEnv",message:"Want to copy .env.example to .env?",initial:!0}]);if(e.company=e.author,e.gitRemote&&!e.gitHomepage){let r=e.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");e.gitHomepage=`${r}#readme`,e.gitIssues=`${r}/issues`}return e};import U from"node:fs/promises";import ue from"node:path";import{existsSync as ie}from"node:fs";var d=async t=>U.readFile(t,"utf-8"),u=async(t,e)=>{await U.mkdir(ue.dirname(t),{recursive:!0}),await U.writeFile(t,e,"utf-8")},fe=async(t,e)=>{await U.mkdir(ue.dirname(e),{recursive:!0}),await U.copyFile(t,e)},x=async t=>{ie(t)&&await U.unlink(t)},S=async t=>{ie(t)&&await U.rm(t,{recursive:!0,force:!0})},Y=async(t,e)=>{let r=await d(t),o=JSON.parse(r),s=e(o);await u(t,JSON.stringify(s,null,2))},f=t=>ie(t);import{exec as ct}from"node:child_process";import{promisify as pt}from"node:util";var Z=pt(ct),ge=async(t,e)=>{try{await Z("git init",{cwd:t}),await Z("git add .",{cwd:t}),await Z('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t}),e&&await Z(`git remote add origin ${e}`,{cwd:t})}catch(r){console.warn("Failed to initialize git repository",r)}};import{exec as lt}from"node:child_process";import{promisify as mt}from"node:util";var oe=mt(lt),he=async(t,e)=>{let r=`${e} install`;try{await oe(r,{cwd:t})}catch(o){throw new Error(`Failed to install dependencies with ${e}: ${o}`)}},W=async(t,e,r)=>{let o=e==="npm"?`${e} run ${r}`:`${e} ${r}`;try{await oe(o,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${r}': ${s}`)}},dt=()=>{let t=process.env.npm_config_user_agent;if(t){if(t.startsWith("yarn"))return"yarn";if(t.startsWith("pnpm"))return"pnpm";if(t.startsWith("bun"))return"bun"}return"npm"},ne=async t=>{let{existsSync:e}=await import("node:fs"),r=await import("node:path");return e(r.join(t,"pnpm-lock.yaml"))?"pnpm":e(r.join(t,"yarn.lock"))?"yarn":e(r.join(t,"bun.lockb"))?"bun":e(r.join(t,"package-lock.json"))?"npm":dt()},ut=async(t,e,r)=>{if(r.length===0)return;let s=`${ft(e)} ${r.join(" ")}`;try{await oe(s,{cwd:t})}catch(i){throw new Error(`Failed to install packages with ${e}: ${i}`)}},ft=t=>{switch(t){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}},xe=async(t,e)=>{let r=await ne(t);await ut(t,r,[e])};import A from"picocolors";var gt={reset:t=>t,red:A.red,green:A.green,yellow:A.yellow,blue:A.blue,cyan:A.cyan,magenta:A.magenta,white:A.white,gray:A.gray,bright:A.bold,dim:A.dim};function H(t,e="reset"){let r=gt[e]??(o=>o);console.log(r(t))}function Q(t){H(`\u2716 ${t}`,"red")}var P=Q;function p(t){H(t)}function Se(){console.log(""),H("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),H("\u2551 \u2551","cyan"),H("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),H("\u2551 \u2551","cyan"),H("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}function ye(t){let{logger:e=n=>console.error(n),exitOnCancel:r=process.env.NODE_ENV!=="test"}=t??{},o=()=>{console.log(""),console.log(""),e("Setup cancelled by user"),console.log(""),r&&process.exit(0)},s=n=>{if(n!==null&&typeof n=="object"&&"code"in n&&n.code==="ERR_USE_AFTER_CLOSE"){o();return}if(n instanceof Error){e(`Uncaught exception: ${n.message}`);return}e(`Uncaught exception: ${String(n)}`)},i=n=>{if(n instanceof Error){e(`Unhandled promise rejection: ${n.message}`);return}e(`Unhandled promise rejection: ${String(n)}`)};return process.on("SIGINT",o),process.on("SIGTERM",o),process.on("uncaughtException",s),process.on("unhandledRejection",i),()=>{process.off("SIGINT",o),process.off("SIGTERM",o),process.off("uncaughtException",s),process.off("unhandledRejection",i)}}var ht=t=>t.charAt(0).toUpperCase()+t.slice(1),O=t=>t.replace(/-([a-z])/g,(e,r)=>r.toUpperCase()),L=t=>ht(O(t));import xt from"ora";var h=xt();import St from"degit";var Pe=async t=>{let e=b("Downloading template...");try{await St("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(t),e.succeed("Template downloaded successfully.")}catch(r){throw e.fail("Failed to download template."),r}};import yt from"node:path";var a={NEXT_CONFIG:"next.config.ts",TAILWIND_CONFIG:"tailwind.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",ESLINT_CONFIG:"eslint.config.mjs",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md"};var w={REDUX_TOOLKIT:"@reduxjs/toolkit",REACT_REDUX:"react-redux",REDUX_PERSIST:"redux-persist",REACT_SECURE_STORAGE:"react-secure-storage",NEXT_INTL:"next-intl",NEXT_THEMES:"next-themes",AXIOS:"axios",HUSKY:"husky",COMMITLINT_CLI:"@commitlint/cli",COMMITLINT_CONFIG:"@commitlint/config-conventional",LINT_STAGED:"lint-staged",COMMITIZEN:"commitizen",CZ_CONVENTIONAL_CHANGELOG:"cz-conventional-changelog"};var Ce=async(t,e)=>{let r=b("Configuring package.json...");try{let o=e.gitRemote,s=e.gitHomepage,i=e.gitIssues;e.gitRemote&&(e.gitRemote.startsWith("git@github.com:")&&(o=e.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"")),s||(s=`${o.replace(/\.git$/,"")}#readme`),i||(i=`${o.replace(/\.git$/,"")}/issues`),o.endsWith(".git")||(o=`${o}.git`)),await Y(yt.join(t,a.PACKAGE_JSON),n=>(n.name=e.projectName,n.version=e.version,n.description=e.description,n.author=e.author,delete n.packageManager,e.gitRemote?(s&&(n.homepage=s),i&&(n.bugs={url:i}),o&&(n.repository={type:"git",url:o})):(delete n.homepage,delete n.bugs,delete n.repository),e.redux||(delete n.dependencies[w.REDUX_TOOLKIT],delete n.dependencies[w.REACT_REDUX],delete n.dependencies[w.REDUX_PERSIST]),e.httpClient!=="none"||e.reactSecureStorage||delete n.dependencies[w.REACT_SECURE_STORAGE],e.i18n||delete n.dependencies[w.NEXT_INTL],e.darkMode||delete n.dependencies[w.NEXT_THEMES],e.httpClient==="none"?delete n.dependencies[w.AXIOS]:e.httpClient==="fetch"&&delete n.dependencies[w.AXIOS],n)),r.succeed("package.json configured.")}catch(o){throw r.fail("Failed to configure package.json."),o}};import m from"node:path";var ve=async(t,e)=>{let r=b("Customizing features...");try{await Pt(t,e),await Ct(t,e),await vt(t,e),await Et(t,e),await Tt(t,e),await wt(t),await It(t),await Rt(t),r.succeed("Features customized.")}catch(o){throw r.fail("Failed to customize features."),o}},Pt=async(t,e)=>{let r=m.join(t,a.HTTP_UTILS),o=e.httpClient!=="none"||e.reactSecureStorage;if(e.httpClient==="none"){if(await S(m.join(t,a.AXIOS_CLIENT)),await S(m.join(t,a.FETCH_CLIENT)),o)await u(m.join(r,"index.ts"),`export * from './token-store';
3
- `),await x(m.join(t,a.CLIENT_UTILS));else{await S(r);let i=m.join(t,a.UTILS_INDEX);if(f(i)){let c=await d(i);c=c.replace(/export \* from '\.\/http';\n/,""),await u(i,c)}await x(m.join(t,a.APP_APIS));let n=m.join(t,a.CONFIG_INDEX);if(f(n)){let c=await d(n);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await u(n,c)}}let s=m.join(t,a.CONSTANTS);if(f(s)){let i=await d(s);i=i.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),i=i.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await u(s,i)}if(await S(m.join(t,a.ERRORS_DIR)),!o){await S(m.join(t,a.COMMON_TYPES_DIR)),await S(m.join(t,a.UTILITY_TYPES_DIR));let i=m.join(t,a.TYPES_INDEX);if(f(i)){let n=await d(i);n=n.replace(/export \* from '\.\/utility';\n/,""),n=n.replace(/export \* from '\.\/common';\n/,""),await u(i,n)}}}else if(e.httpClient==="axios"){await S(m.join(t,a.FETCH_CLIENT));let s=await d(m.join(r,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await u(m.join(r,"index.ts"),s);let i=m.join(t,a.HTTP_TYPES);if(f(i)){let n=await d(i);n=n.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await u(i,n)}}else if(e.httpClient==="fetch"){await S(m.join(t,a.AXIOS_CLIENT));let s=await d(m.join(r,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await u(m.join(r,"index.ts"),s);let i=m.join(t,a.HTTP_TYPES);if(f(i)){let n=await d(i);n=n.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await u(i,n)}}},Ct=async(t,e)=>{e.httpClient!=="none"||e.reactSecureStorage||await S(m.join(t,a.STORAGE_SERVICE))},vt=async(t,e)=>{if(!e.redux){await S(m.join(t,a.STORE)),await S(m.join(t,a.COUNTER_FEATURE)),await x(m.join(t,a.STORE_PROVIDER));let r=m.join(t,a.PROVIDERS_INDEX),o=await d(r);o=o.replace(/export \* from '\.\/StoreProvider';\n/,""),await u(r,o);let s=[m.join(t,a.ROOT_PAGE),m.join(t,a.LOCALE_PAGE)];for(let i of s)if(f(i)){let n=await d(i);n=n.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),n=n.replace(/<Counter\s*\/>\n?/g,""),await u(i,n)}}},Et=async(t,e)=>{if(!e.darkMode){await x(m.join(t,a.THEME_PROVIDER));let r=m.join(t,a.PROVIDERS_INDEX),o=await d(r);o=o.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await u(r,o);let s=m.join(t,a.GLOBALS_CSS);if(f(s)){let i=await d(s);i=i.replace(/@custom-variant dark \(.*?\);\n\n/,""),i=i.replace(/@theme \{[\s\S]*?\}\n/,""),await u(s,i)}if(!e.i18n){let i=m.join(t,a.ROOT_LAYOUT);if(f(i)){let n=await d(i);n=n.replace(/bg-light dark:bg-dark /g,""),await u(i,n)}}}},Tt=async(t,e)=>{if(!e.i18n){await S(m.join(t,a.I18N_DIR)),await S(m.join(t,a.LOCALE_DIR)),await x(m.join(t,a.PROXY)),await x(m.join(t,a.MIDDLEWARE)),await x(m.join(t,a.I18N_TYPES)),await x(m.join(t,a.APP_LOCALES));let r=m.join(t,a.TYPES_INDEX);if(f(r)){let n=await d(r);n=n.replace(/export \* from '\.\/i18n';\n/,""),await u(r,n)}let o=m.join(t,a.CONFIG_INDEX);if(f(o)){let n=await d(o);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await u(o,n)}let s=m.join(t,a.NEXT_CONFIG);if(f(s)){let n=await d(s);n=n.replace(/import createNextIntlPlugin from 'next-intl\/plugin';\n/,""),n=n.replace(/const withNextIntl = createNextIntlPlugin\(\);\n/,""),n=n.replace(/export default withNextIntl\(nextConfig\);/,"export default nextConfig;"),await u(s,n)}let i=m.join(t,a.COUNTER_COMPONENT);if(f(i)){let n=await d(i);n=n.replace(/import\s+\{\s*useTranslations\s*\}\s+from\s+['"]next-intl['"];\n/,""),n=n.replace(/\s*const\s+t\s*=\s*useTranslations\(['"]Count['"]\);\n/,""),n=n.replace(/\{t\('currentCount',\s*\{\s*count:\s*value\s*\}\)\}/g,"{value}"),n=n.replace(/\{t\(['"]increment['"]\)\}/g,"Increment"),n=n.replace(/\{t\(['"]decrement['"]\)\}/g,"Decrement"),n=n.replace(/\{t\(['"]reset['"]\)\}/g,"Reset"),await u(i,n)}}},wt=async t=>{await x(m.join(t,a.LICENSE))},It=async t=>{await x(m.join(t,a.CHANGELOG))},Rt=async t=>{await x(m.join(t,a.NVM_RC)),await x(m.join(t,a.NPM_RC))};import se from"node:path";var Ee=async(t,e)=>{let r=[],o=[];e.redux&&(r.push("import { StoreProvider } from '@/providers';"),o.push("StoreProvider")),e.darkMode&&(r.push("import { CustomThemeProvider } from '@/providers';"),o.push("CustomThemeProvider")),e.i18n&&(r.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),r.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
4
- ${r.join(`
2
+ import{Command as qr}from"commander";import ge from"node:path";import U from"picocolors";import At from"ora";function N(t="",r){let e=At({text:t,...r});return e.start(),e}import bt from"enquirer";var{prompt:_t}=bt,we=async t=>{let r=await _t([{type:"input",name:"projectName",message:"What is the project name?",initial:t||"my-app",skip:!!t,validate:e=>/^[a-z0-9-_]+$/.test(e)?!0:"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:e=>/^\d+\.\d+\.\d+$/.test(e)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:e=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)?!0:"Please enter a valid email address."},{type:"select",name:"packageManager",message:"Which package manager would you like to use?",choices:["npm","yarn","pnpm","bun"],initial:1},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",validate:e=>{if(!e)return!0;let i=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!i.test(e)&&!s.test(e)?"Please enter a valid GitHub repository URL (e.g., https://github.com/user/repo)":!0}},{type:"confirm",name:"keepTemplates",message:"Do you want to keep GitHub issue and pull request templates?",initial:!1},{type:"select",name:"httpClient",message:"Which HTTP client do you want to use?",choices:["axios","fetch","both","none"],initial:1},{type:"confirm",name:"reactSecureStorage",message:"Do you want to include react-secure-storage?",initial:!0,skip:function(){let e=this.state?.answers??this.enquirer?.answers??{};return!!(e.httpClient&&e.httpClient!=="none")}},{type:"confirm",name:"darkMode",message:"Do you want to include Dark Mode (Tailwind + next-themes)?",initial:!0},{type:"confirm",name:"redux",message:"Do you want to include Redux Toolkit?",initial:!0},{type:"confirm",name:"i18n",message:"Do you want to include Internationalization (next-intl)?",initial:!0},{type:"multiselect",name:"communityFiles",message:"Select community files to include:",choices:[{name:"CODE_OF_CONDUCT.md",value:"CODE_OF_CONDUCT.md"},{name:"CONTRIBUTING.md",value:"CONTRIBUTING.md"},{name:"SECURITY.md",value:"SECURITY.md"}],initial:[]},{type:"confirm",name:"readme",message:"Do you want to create a README.md?",initial:!0},{type:"confirm",name:"docker",message:"Do you want to include Docker configuration?",initial:!1},{type:"input",name:"containerName",message:"Docker Container Name:",initial:"next-app",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:e=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(e)?!0:"Invalid Docker container name."},{type:"input",name:"imageName",message:"Docker Image Name:",initial:"nextjs-starter",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:e=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(e)?!0:"Invalid Docker image name (must be lowercase)."},{type:"input",name:"imageTag",message:"Docker Image Tag:",initial:"latest",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:e=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(e)?!0:"Invalid Docker image tag."},{type:"confirm",name:"ci",message:"Do you want to include GitHub Actions (CI/CD)?",initial:!1},{type:"confirm",name:"preCommitHooks",message:"Do you want to setup pre-commit hooks (Husky, Commitlint, Lint-staged)?",initial:!0},{type:"confirm",name:"commitizen",message:"Do you want to setup Commitizen?",initial:!0},{type:"confirm",name:"copyEnv",message:"Want to copy .env.example to .env?",initial:!0}]);if(r.company=r.author,r.gitRemote&&!r.gitHomepage){let e=r.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");r.gitHomepage=`${e}#readme`,r.gitIssues=`${e}/issues`}return r};import J from"node:fs/promises";import Te from"node:path";import{existsSync as de}from"node:fs";var d=async t=>J.readFile(t,"utf-8"),u=async(t,r)=>{await J.mkdir(Te.dirname(t),{recursive:!0}),await J.writeFile(t,r,"utf-8")},M=async(t,r)=>{await J.mkdir(Te.dirname(r),{recursive:!0}),await J.copyFile(t,r)},h=async t=>{de(t)&&await J.unlink(t)},P=async t=>{de(t)&&await J.rm(t,{recursive:!0,force:!0})},Z=async(t,r)=>{let e=await d(t),i=JSON.parse(e),s=r(i);await u(t,JSON.stringify(s,null,2))},m=t=>de(t);import{exec as jt}from"node:child_process";import{promisify as kt}from"node:util";var ie=kt(jt),Ee=async(t,r)=>{try{await ie("git init",{cwd:t}),await ie("git add .",{cwd:t}),await ie('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t}),r&&await ie(`git remote add origin ${r}`,{cwd:t})}catch(e){console.warn("Failed to initialize git repository",e)}};import{exec as Ft}from"node:child_process";import{promisify as Dt}from"node:util";var ue=Dt(Ft),Re=async(t,r)=>{let e=`${r} install`;try{await ue(e,{cwd:t})}catch(i){throw new Error(`Failed to install dependencies with ${r}: ${i}`)}},k=async(t,r,e)=>{let i=r==="npm"?`${r} run ${e}`:`${r} ${e}`;try{await ue(i,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${e}': ${s}`)}},Lt=()=>{let t=process.env.npm_config_user_agent;if(t){if(t.startsWith("yarn"))return"yarn";if(t.startsWith("pnpm"))return"pnpm";if(t.startsWith("bun"))return"bun"}return"npm"},Y=async t=>{let{existsSync:r}=await import("node:fs"),e=await import("node:path");return r(e.join(t,"pnpm-lock.yaml"))?"pnpm":r(e.join(t,"yarn.lock"))?"yarn":r(e.join(t,"bun.lockb"))?"bun":r(e.join(t,"package-lock.json"))?"npm":Lt()},Gt=async(t,r,e)=>{if(e.length===0)return;let s=`${Mt(r)} ${e.join(" ")}`;try{await ue(s,{cwd:t})}catch(o){throw new Error(`Failed to install packages with ${r}: ${o}`)}},Mt=t=>{switch(t){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}},F=async(t,r)=>{let e=await Y(t);await Gt(t,e,[r])};import b from"picocolors";var Ht={reset:t=>t,red:b.red,green:b.green,yellow:b.yellow,blue:b.blue,cyan:b.cyan,magenta:b.magenta,white:b.white,gray:b.gray,bright:b.bold,dim:b.dim};function V(t,r="reset"){let e=Ht[r]??(i=>i);console.log(e(t))}function ne(t){V(`\u2716 ${t}`,"red")}var C=ne;function l(t){V(t)}function Ie(){console.log(""),V("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),V("\u2551 \u2551","cyan"),V("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),V("\u2551 \u2551","cyan"),V("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}function Ne(t){let{logger:r=n=>console.error(n),exitOnCancel:e=process.env.NODE_ENV!=="test"}=t??{},i=()=>{console.log(""),console.log(""),r("Setup cancelled by user"),console.log(""),e&&process.exit(0)},s=n=>{if(n!==null&&typeof n=="object"&&"code"in n&&n.code==="ERR_USE_AFTER_CLOSE"){i();return}if(n instanceof Error){r(`Uncaught exception: ${n.message}`);return}r(`Uncaught exception: ${String(n)}`)},o=n=>{if(n instanceof Error){r(`Unhandled promise rejection: ${n.message}`);return}r(`Unhandled promise rejection: ${String(n)}`)};return process.on("SIGINT",i),process.on("SIGTERM",i),process.on("uncaughtException",s),process.on("unhandledRejection",o),()=>{process.off("SIGINT",i),process.off("SIGTERM",i),process.off("uncaughtException",s),process.off("unhandledRejection",o)}}var Ut=t=>t.charAt(0).toUpperCase()+t.slice(1),A=t=>t.replace(/-([a-z])/g,(r,e)=>e.toUpperCase()),H=t=>Ut(A(t));import Xt from"ora";var x=Xt();import zt from"degit";var Oe=async t=>{let r=N("Downloading template...");try{await zt("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(t),r.succeed("Template downloaded successfully.")}catch(e){throw r.fail("Failed to download template."),e}};import Jt from"node:path";var a={NEXT_CONFIG:"next.config.ts",TAILWIND_CONFIG:"tailwind.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",ESLINT_CONFIG:"eslint.config.mjs",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md"};var R={REDUX_TOOLKIT:"@reduxjs/toolkit",REACT_REDUX:"react-redux",REDUX_PERSIST:"redux-persist",REACT_SECURE_STORAGE:"react-secure-storage",NEXT_INTL:"next-intl",NEXT_THEMES:"next-themes",AXIOS:"axios",HUSKY:"husky",COMMITLINT_CLI:"@commitlint/cli",COMMITLINT_CONFIG:"@commitlint/config-conventional",LINT_STAGED:"lint-staged",COMMITIZEN:"commitizen",CZ_CONVENTIONAL_CHANGELOG:"cz-conventional-changelog"};var $e=async(t,r)=>{let e=N("Configuring package.json...");try{let i=r.gitRemote,s=r.gitHomepage,o=r.gitIssues;r.gitRemote&&(r.gitRemote.startsWith("git@github.com:")&&(i=r.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"")),s||(s=`${i.replace(/\.git$/,"")}#readme`),o||(o=`${i.replace(/\.git$/,"")}/issues`),i.endsWith(".git")||(i=`${i}.git`)),await Z(Jt.join(t,a.PACKAGE_JSON),n=>(n.name=r.projectName,n.version=r.version,n.description=r.description,n.author=r.author,delete n.packageManager,r.gitRemote?(s&&(n.homepage=s),o&&(n.bugs={url:o}),i&&(n.repository={type:"git",url:i})):(delete n.homepage,delete n.bugs,delete n.repository),r.redux||(delete n.dependencies[R.REDUX_TOOLKIT],delete n.dependencies[R.REACT_REDUX],delete n.dependencies[R.REDUX_PERSIST]),r.httpClient!=="none"||r.reactSecureStorage||delete n.dependencies[R.REACT_SECURE_STORAGE],r.i18n||delete n.dependencies[R.NEXT_INTL],r.darkMode||delete n.dependencies[R.NEXT_THEMES],r.httpClient==="none"?delete n.dependencies[R.AXIOS]:r.httpClient==="fetch"&&delete n.dependencies[R.AXIOS],n)),e.succeed("package.json configured.")}catch(i){throw e.fail("Failed to configure package.json."),i}};import f from"node:path";var Ae=async(t,r)=>{let e=N("Customizing features...");try{await Yt(t,r),await Vt(t,r),await Wt(t,r),await Bt(t,r),await Kt(t,r),await qt(t),await Zt(t),await Qt(t),e.succeed("Features customized.")}catch(i){throw e.fail("Failed to customize features."),i}},Yt=async(t,r)=>{let e=f.join(t,a.HTTP_UTILS),i=r.httpClient!=="none"||r.reactSecureStorage;if(r.httpClient==="none"){if(await P(f.join(t,a.AXIOS_CLIENT)),await P(f.join(t,a.FETCH_CLIENT)),i)await u(f.join(e,"index.ts"),`export * from './token-store';
3
+ `),await h(f.join(t,a.CLIENT_UTILS));else{await P(e);let o=f.join(t,a.UTILS_INDEX);if(m(o)){let c=await d(o);c=c.replace(/export \* from '\.\/http';\n/,""),await u(o,c)}await h(f.join(t,a.APP_APIS));let n=f.join(t,a.CONFIG_INDEX);if(m(n)){let c=await d(n);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await u(n,c)}}let s=f.join(t,a.CONSTANTS);if(m(s)){let o=await d(s);o=o.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),o=o.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await u(s,o)}if(await P(f.join(t,a.ERRORS_DIR)),!i){await P(f.join(t,a.COMMON_TYPES_DIR)),await P(f.join(t,a.UTILITY_TYPES_DIR));let o=f.join(t,a.TYPES_INDEX);if(m(o)){let n=await d(o);n=n.replace(/export \* from '\.\/utility';\n/,""),n=n.replace(/export \* from '\.\/common';\n/,""),await u(o,n)}}}else if(r.httpClient==="axios"){await P(f.join(t,a.FETCH_CLIENT));let s=await d(f.join(e,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await u(f.join(e,"index.ts"),s);let o=f.join(t,a.HTTP_TYPES);if(m(o)){let n=await d(o);n=n.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await u(o,n)}}else if(r.httpClient==="fetch"){await P(f.join(t,a.AXIOS_CLIENT));let s=await d(f.join(e,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await u(f.join(e,"index.ts"),s);let o=f.join(t,a.HTTP_TYPES);if(m(o)){let n=await d(o);n=n.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await u(o,n)}}},Vt=async(t,r)=>{r.httpClient!=="none"||r.reactSecureStorage||await P(f.join(t,a.STORAGE_SERVICE))},Wt=async(t,r)=>{if(!r.redux){await P(f.join(t,a.STORE)),await P(f.join(t,a.COUNTER_FEATURE)),await h(f.join(t,a.STORE_PROVIDER));let e=f.join(t,a.PROVIDERS_INDEX),i=await d(e);i=i.replace(/export \* from '\.\/StoreProvider';\n/,""),await u(e,i);let s=[f.join(t,a.ROOT_PAGE),f.join(t,a.LOCALE_PAGE)];for(let o of s)if(m(o)){let n=await d(o);n=n.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),n=n.replace(/<Counter\s*\/>\n?/g,""),await u(o,n)}}},Bt=async(t,r)=>{if(!r.darkMode){await h(f.join(t,a.THEME_PROVIDER));let e=f.join(t,a.PROVIDERS_INDEX),i=await d(e);i=i.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await u(e,i);let s=f.join(t,a.GLOBALS_CSS);if(m(s)){let o=await d(s);o=o.replace(/@custom-variant dark \(.*?\);\n\n/,""),o=o.replace(/@theme \{[\s\S]*?\}\n/,""),await u(s,o)}if(!r.i18n){let o=f.join(t,a.ROOT_LAYOUT);if(m(o)){let n=await d(o);n=n.replace(/bg-light dark:bg-dark /g,""),await u(o,n)}}}},Kt=async(t,r)=>{if(!r.i18n){await P(f.join(t,a.I18N_DIR)),await P(f.join(t,a.LOCALE_DIR)),await h(f.join(t,a.PROXY)),await h(f.join(t,a.MIDDLEWARE)),await h(f.join(t,a.I18N_TYPES)),await h(f.join(t,a.APP_LOCALES));let e=f.join(t,a.TYPES_INDEX);if(m(e)){let n=await d(e);n=n.replace(/export \* from '\.\/i18n';\n/,""),await u(e,n)}let i=f.join(t,a.CONFIG_INDEX);if(m(i)){let n=await d(i);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await u(i,n)}let s=f.join(t,a.NEXT_CONFIG);if(m(s)){let n=await d(s);n=n.replace(/import createNextIntlPlugin from 'next-intl\/plugin';\n/,""),n=n.replace(/const withNextIntl = createNextIntlPlugin\(\);\n/,""),n=n.replace(/export default withNextIntl\(nextConfig\);/,"export default nextConfig;"),await u(s,n)}let o=f.join(t,a.COUNTER_COMPONENT);if(m(o)){let n=await d(o);n=n.replace(/import\s+\{\s*useTranslations\s*\}\s+from\s+['"]next-intl['"];\n/,""),n=n.replace(/\s*const\s+t\s*=\s*useTranslations\(['"]Count['"]\);\n/,""),n=n.replace(/\{t\('currentCount',\s*\{\s*count:\s*value\s*\}\)\}/g,"{value}"),n=n.replace(/\{t\(['"]increment['"]\)\}/g,"Increment"),n=n.replace(/\{t\(['"]decrement['"]\)\}/g,"Decrement"),n=n.replace(/\{t\(['"]reset['"]\)\}/g,"Reset"),await u(o,n)}}},qt=async t=>{await h(f.join(t,a.LICENSE))},Zt=async t=>{await h(f.join(t,a.CHANGELOG))},Qt=async t=>{await h(f.join(t,a.NVM_RC)),await h(f.join(t,a.NPM_RC))};import fe from"node:path";var be=async(t,r)=>{let e=[],i=[];r.redux&&(e.push("import { StoreProvider } from '@/providers';"),i.push("StoreProvider")),r.darkMode&&(e.push("import { CustomThemeProvider } from '@/providers';"),i.push("CustomThemeProvider")),r.i18n&&(e.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),e.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
4
+ ${e.join(`
5
5
  `)}
6
6
 
7
7
  export const RootProvider = ({
8
8
  children,
9
- ${e.i18n?`locale,
9
+ ${r.i18n?`locale,
10
10
  messages,`:""}
11
11
  }: {
12
12
  children: React.ReactNode;
13
- ${e.i18n?`locale: SupportedLocale;
13
+ ${r.i18n?`locale: SupportedLocale;
14
14
  messages: AbstractIntlMessages;`:""}
15
15
  }) => {
16
16
  return (
17
- `,i="{children}";e.i18n&&(i=`<NextIntlClientProvider locale={locale} messages={messages}>
18
- ${i}
19
- </NextIntlClientProvider>`),e.darkMode&&(i=`<CustomThemeProvider>
20
- ${i}
21
- </CustomThemeProvider>`),e.redux&&(i=`<StoreProvider>
22
- ${i}
23
- </StoreProvider>`),i==="{children}"&&(i="<>{children}</>"),s+=` ${i}
17
+ `,o="{children}";r.i18n&&(o=`<NextIntlClientProvider locale={locale} messages={messages}>
18
+ ${o}
19
+ </NextIntlClientProvider>`),r.darkMode&&(o=`<CustomThemeProvider>
20
+ ${o}
21
+ </CustomThemeProvider>`),r.redux&&(o=`<StoreProvider>
22
+ ${o}
23
+ </StoreProvider>`),o==="{children}"&&(o="<>{children}</>"),s+=` ${o}
24
24
  );
25
25
  };
26
- `,await u(se.join(t,a.ROOT_PROVIDER),s)},Te=async(t,e)=>{if(!e.i18n){let r=`import type { Metadata } from 'next';
26
+ `,await u(fe.join(t,a.ROOT_PROVIDER),s)},_e=async(t,r)=>{if(!r.i18n){let e=`import type { Metadata } from 'next';
27
27
  import '@/styles/globals.css';
28
28
  import { Livvic } from 'next/font/google';
29
29
  import { RootProvider } from '@/providers';
@@ -36,8 +36,8 @@ const livvic = Livvic({
36
36
  });
37
37
 
38
38
  export const metadata: Metadata = {
39
- title: '${e.projectName}',
40
- description: '${e.description}',
39
+ title: '${r.projectName}',
40
+ description: '${r.description}',
41
41
  };
42
42
 
43
43
  export default function RootLayout({
@@ -46,8 +46,8 @@ export default function RootLayout({
46
46
  children: React.ReactNode;
47
47
  }>) {
48
48
  return (
49
- <html lang="en" suppressHydrationWarning={${e.darkMode?"true":"false"}}>
50
- <body className={\`\${livvic.variable} ${e.darkMode?"bg-light dark:bg-dark ":""}antialiased\`}>
49
+ <html lang="en" suppressHydrationWarning={${r.darkMode?"true":"false"}}>
50
+ <body className={\`\${livvic.variable} ${r.darkMode?"bg-light dark:bg-dark ":""}antialiased\`}>
51
51
  <RootProvider>
52
52
  {children}
53
53
  </RootProvider>
@@ -55,53 +55,53 @@ export default function RootLayout({
55
55
  </html>
56
56
  );
57
57
  }
58
- `;await u(se.join(t,a.ROOT_LAYOUT),r);let o=e.redux?`import { Counter } from '@/features/counter';
58
+ `;await u(fe.join(t,a.ROOT_LAYOUT),e);let i=r.redux?`import { Counter } from '@/features/counter';
59
59
 
60
- `:"",s=e.redux?`
61
- <Counter />`:"",i=`${o}export default function Home() {
60
+ `:"",s=r.redux?`
61
+ <Counter />`:"",o=`${i}export default function Home() {
62
62
  return (
63
63
  <div className="flex min-h-screen flex-col items-center justify-center p-24">
64
- <h1 className="text-4xl font-bold">Welcome to ${e.projectName}</h1>
64
+ <h1 className="text-4xl font-bold">Welcome to ${r.projectName}</h1>
65
65
  <p className="mt-4 text-xl">Get started by editing src/app/page.tsx</p>${s}
66
66
  </div>
67
67
  );
68
68
  }
69
- `;await u(se.join(t,a.ROOT_PAGE),i)}};import y from"node:path";import{readdir as we}from"node:fs/promises";var Ie=async(t,e)=>{await Nt(t,e),await $t(t,e),await Ot(t,e),await bt(t,e),await At(t,e),await jt(t,e),await _t(t,e)},Nt=async(t,e)=>{e.preCommitHooks||(await S(y.join(t,a.HUSKY_DIR)),await x(y.join(t,a.COMMITLINT_CONFIG)),await x(y.join(t,a.LINTSTAGED_RC)),await Y(y.join(t,a.PACKAGE_JSON),r=>(delete r.devDependencies[w.HUSKY],delete r.devDependencies[w.COMMITLINT_CLI],delete r.devDependencies[w.COMMITLINT_CONFIG],delete r.devDependencies[w.LINT_STAGED],delete r.scripts.prepare,delete r.scripts.postinstall,delete r.commitlint,delete r["lint-staged"],r)))},$t=async(t,e)=>{e.commitizen||(await x(y.join(t,a.CZRC)),await Y(y.join(t,a.PACKAGE_JSON),r=>(delete r.devDependencies[w.COMMITIZEN],delete r.devDependencies[w.CZ_CONVENTIONAL_CHANGELOG],delete r.config?.commitizen,r.config&&Object.keys(r.config).length===0&&delete r.config,delete r.scripts.commit,r)))},Ot=async(t,e)=>{e.ci||await S(y.join(t,a.GITHUB_WORKFLOWS))},bt=async(t,e)=>{let r=y.join(t,a.GITHUB_DIR);if(!e.keepTemplates)await S(y.join(r,a.GITHUB_ISSUE_TEMPLATE)),await x(y.join(r,a.GITHUB_PR_TEMPLATE));else{let o=y.join(r,a.GITHUB_ISSUE_TEMPLATE),s=y.join(r,a.GITHUB_PR_TEMPLATE),i=n=>n.replace(/Teispace/g,e.company).replace(/support@teispace\.com/g,e.email).replace(/Next\.js Starter/g,e.projectName).replace(/\[AUTHOR\]/g,e.author).replace(/\[COMPANY\]/g,e.company).replace(/\[EMAIL\]/g,e.email);if(f(s)){let n=await d(s);n=i(n),await u(s,n)}try{if(f(o)){let n=await we(o);for(let c of n){let l=y.join(o,c),g=await d(l);g=i(g),await u(l,g)}}}catch{}}},At=async(t,e)=>{let r=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let o of r)e.communityFiles.includes(o)||await x(y.join(t,o))},jt=async(t,e)=>{if(e.docker){let r=y.join(t,a.ENV_EXAMPLE);if(f(r)){let o=await d(r),s=(i,n)=>{let c=new RegExp(`${i}=.*`);c.test(o)?o=o.replace(c,`${i}=${n}`):o+=`${i}=${n}
70
- `};s("CONTAINER_NAME",e.containerName||"next-app"),s("IMAGE_NAME",e.imageName||"nextjs-starter"),s("IMAGE_TAG",e.imageTag||"latest"),await u(r,o)}}else{await x(y.join(t,a.DOCKERFILE)),await x(y.join(t,a.DOCKER_COMPOSE)),await x(y.join(t,a.DOCKERIGNORE));let r=y.join(t,a.ENV_EXAMPLE);if(f(r)){let o=await d(r);o=o.replace(/# Docker Compose Configuration\n/,""),o=o.replace(/CONTAINER_NAME=.*\n/,""),o=o.replace(/IMAGE_NAME=.*\n/,""),o=o.replace(/IMAGE_TAG=.*\n/,""),await u(r,o)}}},_t=async(t,e)=>{let r=async i=>{let n=await we(i,{withFileTypes:!0}),c=[];for(let l of n){let g=y.join(i,l.name);l.isDirectory()&&l.name!=="node_modules"&&l.name!==".git"?c.push(...await r(g)):l.isFile()&&l.name.toLowerCase()==="readme.md"&&c.push(g)}return c},o=await r(t),s=y.join(t,a.README);for(let i of o)i!==s&&await x(i);if(e.readme){let i=`# ${e.projectName}
69
+ `;await u(fe.join(t,a.ROOT_PAGE),o)}};import y from"node:path";import{readdir as je}from"node:fs/promises";var ke=async(t,r)=>{await er(t,r),await tr(t,r),await rr(t,r),await or(t,r),await ir(t,r),await nr(t,r),await sr(t,r)},er=async(t,r)=>{r.preCommitHooks||(await P(y.join(t,a.HUSKY_DIR)),await h(y.join(t,a.COMMITLINT_CONFIG)),await h(y.join(t,a.LINTSTAGED_RC)),await Z(y.join(t,a.PACKAGE_JSON),e=>(delete e.devDependencies[R.HUSKY],delete e.devDependencies[R.COMMITLINT_CLI],delete e.devDependencies[R.COMMITLINT_CONFIG],delete e.devDependencies[R.LINT_STAGED],delete e.scripts.prepare,delete e.scripts.postinstall,delete e.commitlint,delete e["lint-staged"],e)))},tr=async(t,r)=>{r.commitizen||(await h(y.join(t,a.CZRC)),await Z(y.join(t,a.PACKAGE_JSON),e=>(delete e.devDependencies[R.COMMITIZEN],delete e.devDependencies[R.CZ_CONVENTIONAL_CHANGELOG],delete e.config?.commitizen,e.config&&Object.keys(e.config).length===0&&delete e.config,delete e.scripts.commit,e)))},rr=async(t,r)=>{r.ci||await P(y.join(t,a.GITHUB_WORKFLOWS))},or=async(t,r)=>{let e=y.join(t,a.GITHUB_DIR);if(!r.keepTemplates)await P(y.join(e,a.GITHUB_ISSUE_TEMPLATE)),await h(y.join(e,a.GITHUB_PR_TEMPLATE));else{let i=y.join(e,a.GITHUB_ISSUE_TEMPLATE),s=y.join(e,a.GITHUB_PR_TEMPLATE),o=n=>n.replace(/Teispace/g,r.company).replace(/support@teispace\.com/g,r.email).replace(/Next\.js Starter/g,r.projectName).replace(/\[AUTHOR\]/g,r.author).replace(/\[COMPANY\]/g,r.company).replace(/\[EMAIL\]/g,r.email);if(m(s)){let n=await d(s);n=o(n),await u(s,n)}try{if(m(i)){let n=await je(i);for(let c of n){let p=y.join(i,c),g=await d(p);g=o(g),await u(p,g)}}}catch{}}},ir=async(t,r)=>{let e=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let i of e)r.communityFiles.includes(i)||await h(y.join(t,i))},nr=async(t,r)=>{if(r.docker){let e=y.join(t,a.ENV_EXAMPLE);if(m(e)){let i=await d(e),s=(o,n)=>{let c=new RegExp(`${o}=.*`);c.test(i)?i=i.replace(c,`${o}=${n}`):i+=`${o}=${n}
70
+ `};s("CONTAINER_NAME",r.containerName||"next-app"),s("IMAGE_NAME",r.imageName||"nextjs-starter"),s("IMAGE_TAG",r.imageTag||"latest"),await u(e,i)}}else{await h(y.join(t,a.DOCKERFILE)),await h(y.join(t,a.DOCKER_COMPOSE)),await h(y.join(t,a.DOCKERIGNORE));let e=y.join(t,a.ENV_EXAMPLE);if(m(e)){let i=await d(e);i=i.replace(/# Docker Compose Configuration\n/,""),i=i.replace(/CONTAINER_NAME=.*\n/,""),i=i.replace(/IMAGE_NAME=.*\n/,""),i=i.replace(/IMAGE_TAG=.*\n/,""),await u(e,i)}}},sr=async(t,r)=>{let e=async o=>{let n=await je(o,{withFileTypes:!0}),c=[];for(let p of n){let g=y.join(o,p.name);p.isDirectory()&&p.name!=="node_modules"&&p.name!==".git"?c.push(...await e(g)):p.isFile()&&p.name.toLowerCase()==="readme.md"&&c.push(g)}return c},i=await e(t),s=y.join(t,a.README);for(let o of i)o!==s&&await h(o);if(r.readme){let o=`# ${r.projectName}
71
71
 
72
- ${e.description}
72
+ ${r.description}
73
73
 
74
74
  ## Getting Started
75
75
 
76
76
  First, run the development server:
77
77
 
78
78
  \`\`\`bash
79
- ${e.packageManager==="npm"?"npm run dev":e.packageManager+" dev"}
79
+ ${r.packageManager==="npm"?"npm run dev":r.packageManager+" dev"}
80
80
  \`\`\`
81
81
 
82
82
  Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
83
- `;await u(s,i)}else await x(s)};var Re=t=>{t.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async e=>{await kt(e)})},kt=async t=>{Se(),p("Welcome to the Teispace Next.js App Creator!"),p("");let e=await de(t),r=ae.resolve(process.cwd(),e.projectName);f(r)&&(console.error(G.red(`Error: Directory ${e.projectName} already exists.`)),process.exit(1));let o=b("Initializing project..."),s=async()=>{if(f(r)){o.stop(),console.log(G.yellow(`
84
- Cleaning up: Deleting directory ${e.projectName}...`));try{await S(r),console.log(G.green("Cleanup successful."))}catch(n){console.error(G.red(`Failed to clean up directory ${e.projectName}:`),n)}}},i=async()=>{console.log(G.red(`
85
- Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",i),process.on("SIGTERM",i);try{if(await Pe(r),await Ce(r,e),await ve(r,e),o.text="Generating code...",await Ee(r,e),await Te(r,e),o.text="Setting up developer tools...",await Ie(r,e),o.text="Initializing Git...",await ge(r,e.gitRemote),o.text="Installing dependencies...",await he(r,e.packageManager),o.text="Formatting and Linting...",await W(r,e.packageManager,"format"),await W(r,e.packageManager,"lint:fix"),e.copyEnv){o.text="Creating .env file...";let n=ae.join(r,".env.example"),c=ae.join(r,".env");f(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",i),process.off("SIGTERM",i),o.succeed(G.green(`Project ${e.projectName} created successfully!`)),p(""),p("To get started:"),p(G.cyan(` cd ${e.projectName}`)),p(G.cyan(` ${e.packageManager==="npm"?"npm run dev":e.packageManager+" dev"}`)),p("")}catch(n){o.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import E from"picocolors";import le from"node:path";import Dt from"enquirer";var{prompt:Ft}=Dt,Ne=async(t,e,r,o,s,i,n)=>{let c=[];t||c.push({type:"input",name:"featureName",message:"What is the feature name?",initial:"my-feature",validate:g=>/^[a-z0-9-]+$/.test(g)?!0:"Feature name must be lowercase and contain only alphanumeric characters and hyphens."}),e&&o===void 0&&s===void 0&&(c.push({type:"confirm",name:"createStore",message:"Generate Redux store for this feature?",initial:!0}),c.push({type:"confirm",name:"persistStore",message:"Enable persistence for this store?",initial:!1,skip(){return!this.state.answers.createStore}})),r&&r!=="none"&&i===void 0&&n===void 0&&(c.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),r==="both"&&c.push({type:"select",name:"selectedHttpClient",message:"Which HTTP client to use for the service?",choices:["fetch","axios"],initial:0,skip(){return!this.state.answers.createService}}));let l=c.length>0?await Ft(c):{};return{featureName:t||l.featureName,hasRedux:e||!1,createStore:o===!0?!1:s!==void 0?!0:l.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:l.persistStore||!1,httpClient:r||"none",createService:i===!0?!1:n!==void 0?!0:l.createService||!1,selectedHttpClient:n||l.selectedHttpClient||(r==="both"?"fetch":r!=="none"?r:void 0)}};import{readFile as Lt,access as ce}from"node:fs/promises";import V from"node:path";var z=async t=>{let e=!1,r=!1,o=!1,s=!1;try{let i=V.join(t,"package.json"),n=await Lt(i,"utf-8"),c=JSON.parse(n),l={...c.dependencies,...c.devDependencies};e=!!(l["@reduxjs/toolkit"]&&l["react-redux"]),r=!!l.axios,s=!!l["next-intl"];let g=V.join(t,"src","lib","utils","http","axios-client");try{await ce(g),r=r&&!0}catch{r=!1}let R=V.join(t,"src","lib","utils","http","fetch-client");try{await ce(R),o=!0}catch{o=!1}let C;return r&&o?C="both":r?C="axios":o?C="fetch":C="none",{hasRedux:e,httpClient:C,hasI18n:s}}catch(i){throw new Error(`Failed to detect project setup: ${i}`)}},$e=async(t,e,r=V.join("src","features"))=>{let o=V.join(t,r,e);try{return await ce(o),!0}catch{return!1}};import{writeFile as D,mkdir as J}from"node:fs/promises";import N from"node:path";var Oe=async t=>{let{featurePath:e}=t;await J(N.join(e,"components"),{recursive:!0}),await J(N.join(e,"hooks"),{recursive:!0}),await J(N.join(e,"types"),{recursive:!0}),t.createStore&&await J(N.join(e,"store"),{recursive:!0}),t.createService&&await J(N.join(e,"services"),{recursive:!0}),await Gt(t),await Mt(t),await Ut(t),await zt(t),t.createStore&&await Ht(t),t.createService&&t.httpClient&&await Xt(t)};var Gt=async t=>{let{featureName:e,featurePath:r}=t,o=L(e),s=`use${o}`,i=`'use client';
83
+ `;await u(s,o)}else await h(s)};var Fe=t=>{t.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async r=>{await ar(r)})},ar=async t=>{Ie(),l("Welcome to the Teispace Next.js App Creator!"),l("");let r=await we(t),e=ge.resolve(process.cwd(),r.projectName);m(e)&&(console.error(U.red(`Error: Directory ${r.projectName} already exists.`)),process.exit(1));let i=N("Initializing project..."),s=async()=>{if(m(e)){i.stop(),console.log(U.yellow(`
84
+ Cleaning up: Deleting directory ${r.projectName}...`));try{await P(e),console.log(U.green("Cleanup successful."))}catch(n){console.error(U.red(`Failed to clean up directory ${r.projectName}:`),n)}}},o=async()=>{console.log(U.red(`
85
+ Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await Oe(e),await $e(e,r),await Ae(e,r),i.text="Generating code...",await be(e,r),await _e(e,r),i.text="Setting up developer tools...",await ke(e,r),i.text="Initializing Git...",await Ee(e,r.gitRemote),i.text="Installing dependencies...",await Re(e,r.packageManager),i.text="Formatting and Linting...",await k(e,r.packageManager,"format"),await k(e,r.packageManager,"lint:fix"),r.copyEnv){i.text="Creating .env file...";let n=ge.join(e,".env.example"),c=ge.join(e,".env");m(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",o),process.off("SIGTERM",o),i.succeed(U.green(`Project ${r.projectName} created successfully!`)),l(""),l("To get started:"),l(U.cyan(` cd ${r.projectName}`)),l(U.cyan(` ${r.packageManager==="npm"?"npm run dev":r.packageManager+" dev"}`)),l("")}catch(n){i.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import E from"picocolors";import Pe from"node:path";import cr from"enquirer";var{prompt:lr}=cr,De=async(t,r,e,i,s,o,n)=>{let c=[];t||c.push({type:"input",name:"featureName",message:"What is the feature name?",initial:"my-feature",validate:g=>/^[a-z0-9-]+$/.test(g)?!0:"Feature name must be lowercase and contain only alphanumeric characters and hyphens."}),r&&i===void 0&&s===void 0&&(c.push({type:"confirm",name:"createStore",message:"Generate Redux store for this feature?",initial:!0}),c.push({type:"confirm",name:"persistStore",message:"Enable persistence for this store?",initial:!1,skip(){return!this.state.answers.createStore}})),e&&e!=="none"&&o===void 0&&n===void 0&&(c.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),e==="both"&&c.push({type:"select",name:"selectedHttpClient",message:"Which HTTP client to use for the service?",choices:["fetch","axios"],initial:0,skip(){return!this.state.answers.createService}}));let p=c.length>0?await lr(c):{};return{featureName:t||p.featureName,hasRedux:r||!1,createStore:i===!0?!1:s!==void 0?!0:p.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:p.persistStore||!1,httpClient:e||"none",createService:o===!0?!1:n!==void 0?!0:p.createService||!1,selectedHttpClient:n||p.selectedHttpClient||(e==="both"?"fetch":e!=="none"?e:void 0)}};import{readFile as pr,access as xe}from"node:fs/promises";import Q from"node:path";var K=async t=>{let r=!1,e=!1,i=!1,s=!1;try{let o=Q.join(t,"package.json"),n=await pr(o,"utf-8"),c=JSON.parse(n),p={...c.dependencies,...c.devDependencies};r=!!(p["@reduxjs/toolkit"]&&p["react-redux"]),e=!!p.axios,s=!!p["next-intl"];let g=Q.join(t,"src","lib","utils","http","axios-client");try{await xe(g),e=e&&!0}catch{e=!1}let v=Q.join(t,"src","lib","utils","http","fetch-client");try{await xe(v),i=!0}catch{i=!1}let S;return e&&i?S="both":e?S="axios":i?S="fetch":S="none",{hasRedux:r,httpClient:S,hasI18n:s}}catch(o){throw new Error(`Failed to detect project setup: ${o}`)}},Le=async(t,r,e=Q.join("src","features"))=>{let i=Q.join(t,e,r);try{return await xe(i),!0}catch{return!1}};import{writeFile as D,mkdir as ee}from"node:fs/promises";import O from"node:path";var Ge=async t=>{let{featurePath:r}=t;await ee(O.join(r,"components"),{recursive:!0}),await ee(O.join(r,"hooks"),{recursive:!0}),await ee(O.join(r,"types"),{recursive:!0}),t.createStore&&await ee(O.join(r,"store"),{recursive:!0}),t.createService&&await ee(O.join(r,"services"),{recursive:!0}),await mr(t),await dr(t),await ur(t),await xr(t),t.createStore&&await fr(t),t.createService&&t.httpClient&&await gr(t)};var mr=async t=>{let{featureName:r,featurePath:e}=t,i=H(r),s=`use${i}`,o=`'use client';
86
86
  import { ${s} } from '../hooks/${s}';
87
87
 
88
- export function ${o}() {
88
+ export function ${i}() {
89
89
  const {} = ${s}();
90
90
 
91
91
  return (
92
92
  <div>
93
- <h2>${o} Component</h2>
93
+ <h2>${i} Component</h2>
94
94
  {/* Add your component UI here */}
95
95
  </div>
96
96
  );
97
97
  }
98
98
 
99
- export default ${o};
100
- `;await D(N.join(r,"components",`${o}.tsx`),i)},Mt=async t=>{let{featureName:e,featurePath:r,createStore:o}=t,s=L(e),i=`use${s}`,n;o?n=`'use client';
99
+ export default ${i};
100
+ `;await D(O.join(e,"components",`${i}.tsx`),o)},dr=async t=>{let{featureName:r,featurePath:e,createStore:i}=t,s=H(r),o=`use${s}`,n;i?n=`'use client';
101
101
  import { useAppDispatch, useAppSelector } from '@/store/hooks';
102
- import { select${s}State, setLoading, setError } from '../store/${e}.selectors';
102
+ import { select${s}State, setLoading, setError } from '../store/${r}.selectors';
103
103
 
104
- export const ${i} = () => {
104
+ export const ${o} = () => {
105
105
  const dispatch = useAppDispatch();
106
106
  const state = useAppSelector(select${s}State);
107
107
 
@@ -124,7 +124,7 @@ export const ${i} = () => {
124
124
  `:n=`'use client';
125
125
  import { useState } from 'react';
126
126
 
127
- export const ${i} = () => {
127
+ export const ${o} = () => {
128
128
  // Add your state and logic here
129
129
  const [state, setState] = useState({});
130
130
 
@@ -133,13 +133,13 @@ export const ${i} = () => {
133
133
  // Add your methods here
134
134
  } as const;
135
135
  };
136
- `,await D(N.join(r,"hooks",`${i}.ts`),n)},Ut=async t=>{let{featureName:e,featurePath:r,createStore:o}=t,n=`export interface ${`${L(e)}State`} {
136
+ `,await D(O.join(e,"hooks",`${o}.ts`),n)},ur=async t=>{let{featureName:r,featurePath:e,createStore:i}=t,n=`export interface ${`${H(r)}State`} {
137
137
  // Add your state properties here
138
- ${o?`loading: boolean;
138
+ ${i?`loading: boolean;
139
139
  error: string | null;`:"// example: value: string;"}
140
140
  }
141
- `;await D(N.join(r,"types",`${e}.types.ts`),n)},Ht=async t=>{let{featureName:e,featurePath:r,persistStore:o}=t,s=L(e),i=O(e),n=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
142
- import { ${s}State } from '../types/${e}.types';
141
+ `;await D(O.join(e,"types",`${r}.types.ts`),n)},fr=async t=>{let{featureName:r,featurePath:e,persistStore:i}=t,s=H(r),o=A(r),n=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
142
+ import { ${s}State } from '../types/${r}.types';
143
143
 
144
144
  const initialState: ${s}State = {
145
145
  loading: false,
@@ -147,8 +147,8 @@ const initialState: ${s}State = {
147
147
  // Add your initial state here
148
148
  };
149
149
 
150
- export const ${i}Slice = createSlice({
151
- name: '${i}',
150
+ export const ${o}Slice = createSlice({
151
+ name: '${o}',
152
152
  initialState,
153
153
  reducers: {
154
154
  setLoading: (state, action: PayloadAction<boolean>) => {
@@ -164,26 +164,26 @@ export const ${i}Slice = createSlice({
164
164
  },
165
165
  });
166
166
 
167
- export const { setLoading, setError, resetState } = ${i}Slice.actions;
167
+ export const { setLoading, setError, resetState } = ${o}Slice.actions;
168
168
 
169
- export const ${i}Reducer = ${i}Slice.reducer;
170
- `;await D(N.join(r,"store",`${e}.slice.ts`),n);let c=`import { RootState } from '@/store/rootReducer';
169
+ export const ${o}Reducer = ${o}Slice.reducer;
170
+ `;await D(O.join(e,"store",`${r}.slice.ts`),n);let c=`import { RootState } from '@/store/rootReducer';
171
171
 
172
- export const select${s}State = (state: RootState) => state.${i};
173
- export { setLoading, setError, resetState } from './${e}.slice';
174
- `;if(await D(N.join(r,"store",`${e}.selectors.ts`),c),o){let g=`import { PersistConfig } from 'redux-persist';
172
+ export const select${s}State = (state: RootState) => state.${o};
173
+ export { setLoading, setError, resetState } from './${r}.slice';
174
+ `;if(await D(O.join(e,"store",`${r}.selectors.ts`),c),i){let g=`import { PersistConfig } from 'redux-persist';
175
175
  import storage from 'redux-persist/lib/storage';
176
- import { ${s}State } from '../types/${e}.types';
176
+ import { ${s}State } from '../types/${r}.types';
177
177
 
178
- export const ${i}PersistConfig: PersistConfig<${s}State> = {
179
- key: '${i}',
178
+ export const ${o}PersistConfig: PersistConfig<${s}State> = {
179
+ key: '${o}',
180
180
  storage,
181
181
  // whitelist: ['someField'], // Specify which fields to persist
182
182
  };
183
- `;await D(N.join(r,"store","persist.ts"),g)}let l=`export * from './${e}.slice';
184
- export * from './${e}.selectors';${o?`
183
+ `;await D(O.join(e,"store","persist.ts"),g)}let p=`export * from './${r}.slice';
184
+ export * from './${r}.selectors';${i?`
185
185
  export * from './persist';`:""}
186
- `;await D(N.join(r,"store","index.ts"),l)},Xt=async t=>{let{featureName:e,featurePath:r,httpClient:o}=t,s=O(e),i;o==="axios"?i=`import { AppApis } from '@/lib/config';
186
+ `;await D(O.join(e,"store","index.ts"),p)},gr=async t=>{let{featureName:r,featurePath:e,httpClient:i}=t,s=A(r),o;i==="axios"?o=`import { AppApis } from '@/lib/config';
187
187
  import { axiosClient } from '@/lib/utils/http';
188
188
  import { ResultAsync } from '@/types';
189
189
 
@@ -192,7 +192,7 @@ export const ${s}Service = {
192
192
  return axiosClient.get<string>(AppApis.${s}.getAll);
193
193
  },
194
194
  };
195
- `:i=`import { AppApis } from '@/lib/config';
195
+ `:o=`import { AppApis } from '@/lib/config';
196
196
  import { fetchClient } from '@/lib/utils/http';
197
197
  import { ResultAsync } from '@/types';
198
198
 
@@ -201,50 +201,50 @@ export const ${s}Service = {
201
201
  return fetchClient.get<string>(AppApis.${s}.getAll);
202
202
  },
203
203
  };
204
- `,await D(N.join(r,"services",`${e}.service.ts`),i)},zt=async t=>{let{featureName:e,featurePath:r,createStore:o,createService:s}=t,i=L(e),n=`export { default as ${i} } from './components/${i}';
205
- export { use${i} } from './hooks/use${i}';
206
- export * from './types/${e}.types';${o?`
204
+ `,await D(O.join(e,"services",`${r}.service.ts`),o)},xr=async t=>{let{featureName:r,featurePath:e,createStore:i,createService:s}=t,o=H(r),n=`export { default as ${o} } from './components/${o}';
205
+ export { use${o} } from './hooks/use${o}';
206
+ export * from './types/${r}.types';${i?`
207
207
  export * from './store';`:""}${s?`
208
- export * from './services/${e}.service';`:""}
209
- `;await D(N.join(r,"index.ts"),n)};import{readFile as be,writeFile as Ae}from"node:fs/promises";import pe from"node:path";var je=async(t,e,r,o=pe.join("src","features"))=>{let s=pe.join(t,"src","store","rootReducer.ts");try{let i=await be(s,"utf-8"),n=O(e),c=`${n}Reducer`,l=r?`${n}PersistConfig`:"",g=o.replace(/^src\//,"@/"),R=r?`import { ${c}, ${l} } from '${g}/${e}/store';`:`import { ${c} } from '${g}/${e}/store';`,C=/import\s+.*\s+from\s+['"].*['"];?\n/g,T=i.match(C);if(T&&T.length>0){let I=T[T.length-1],k=i.lastIndexOf(I);i=i.slice(0,k+I.length)+R+`
210
- `+i.slice(k+I.length)}else i=R+`
211
- `+i;let v=/combineReducers\(\{([^}]*)\}\)/s,_=i.match(v);if(_){let I=_[1],k=r?`
212
- ${n}: persistReducer(${l}, ${c}),`:`
213
- ${n}: ${c},`,re=I.trimEnd()+k;i=i.replace(v,`combineReducers({${re}
214
- })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await Ae(s,i)}catch(i){throw new Error(`Failed to register feature in rootReducer: ${i}`)}},_e=async(t,e,r,o)=>{let s=pe.join(t,"src","store","rootReducer.ts");try{let i=await be(s,"utf-8"),n=O(e),c=`${n}Reducer`,l=r?`${n}PersistConfig`:"",g=o.replace(/^src\//,"@/"),R=r?`import { ${c}, ${l} } from '${g}/${e}';`:`import { ${c} } from '${g}/${e}';`,C=/import\s+.*\s+from\s+['"].*['"];?\n/g,T=i.match(C);if(T&&T.length>0){let I=T[T.length-1],k=i.lastIndexOf(I);i=i.slice(0,k+I.length)+R+`
215
- `+i.slice(k+I.length)}else i=R+`
216
- `+i;let v=/combineReducers\(\{([^}]*)\}\)/s,_=i.match(v);if(_){let I=_[1],k=r?`
217
- ${n}: persistReducer(${l}, ${c}),`:`
218
- ${n}: ${c},`,re=I.trimEnd()+k;i=i.replace(v,`combineReducers({${re}
219
- })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await Ae(s,i)}catch(i){throw new Error(`Failed to register slice in rootReducer: ${i}`)}};import{readFile as Yt,writeFile as Wt}from"node:fs/promises";import Vt from"node:path";var ee=async t=>{let{serviceName:e,projectPath:r}=t,o=O(e),s=Vt.join(r,"src","lib","config","app-apis.ts");try{let i=await Yt(s,"utf-8");if(i.includes(`${o}:`))return;if(!i.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");let c=` ${o}: {
220
- base: \`\${API_PREFIX}/${e}\`,
221
- getAll: \`\${API_PREFIX}/${e}\`,
222
- },`,l=/(\s*)\} as const;/;if(!i.match(l))throw new Error("Could not find closing brace of AppApis object");let R=i.lastIndexOf("} as const;"),C=i.substring(0,R),T=i.substring(R),v=C.trim().endsWith(","),_=C.match(/:\s*\{[^}]*\},\s*$/),I;_||v?I=`${C}
208
+ export * from './services/${r}.service';`:""}
209
+ `;await D(O.join(e,"index.ts"),n)};import{readFile as Me,writeFile as He}from"node:fs/promises";import he from"node:path";var Ue=async(t,r,e,i=he.join("src","features"))=>{let s=he.join(t,"src","store","rootReducer.ts");try{let o=await Me(s,"utf-8"),n=A(r),c=`${n}Reducer`,p=e?`${n}PersistConfig`:"",g=i.replace(/^src\//,"@/"),v=e?`import { ${c}, ${p} } from '${g}/${r}/store';`:`import { ${c} } from '${g}/${r}/store';`,S=/import\s+.*\s+from\s+['"].*['"];?\n/g,w=o.match(S);if(w&&w.length>0){let I=w[w.length-1],j=o.lastIndexOf(I);o=o.slice(0,j+I.length)+v+`
210
+ `+o.slice(j+I.length)}else o=v+`
211
+ `+o;let T=/combineReducers\(\{([^}]*)\}\)/s,_=o.match(T);if(_){let I=_[1],j=e?`
212
+ ${n}: persistReducer(${p}, ${c}),`:`
213
+ ${n}: ${c},`,me=I.trimEnd()+j;o=o.replace(T,`combineReducers({${me}
214
+ })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await He(s,o)}catch(o){throw new Error(`Failed to register feature in rootReducer: ${o}`)}},Xe=async(t,r,e,i)=>{let s=he.join(t,"src","store","rootReducer.ts");try{let o=await Me(s,"utf-8"),n=A(r),c=`${n}Reducer`,p=e?`${n}PersistConfig`:"",g=i.replace(/^src\//,"@/"),v=e?`import { ${c}, ${p} } from '${g}/${r}';`:`import { ${c} } from '${g}/${r}';`,S=/import\s+.*\s+from\s+['"].*['"];?\n/g,w=o.match(S);if(w&&w.length>0){let I=w[w.length-1],j=o.lastIndexOf(I);o=o.slice(0,j+I.length)+v+`
215
+ `+o.slice(j+I.length)}else o=v+`
216
+ `+o;let T=/combineReducers\(\{([^}]*)\}\)/s,_=o.match(T);if(_){let I=_[1],j=e?`
217
+ ${n}: persistReducer(${p}, ${c}),`:`
218
+ ${n}: ${c},`,me=I.trimEnd()+j;o=o.replace(T,`combineReducers({${me}
219
+ })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await He(s,o)}catch(o){throw new Error(`Failed to register slice in rootReducer: ${o}`)}};import{readFile as hr,writeFile as Pr}from"node:fs/promises";import Sr from"node:path";var se=async t=>{let{serviceName:r,projectPath:e}=t,i=A(r),s=Sr.join(e,"src","lib","config","app-apis.ts");try{let o=await hr(s,"utf-8");if(o.includes(`${i}:`))return;if(!o.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");let c=` ${i}: {
220
+ base: \`\${API_PREFIX}/${r}\`,
221
+ getAll: \`\${API_PREFIX}/${r}\`,
222
+ },`,p=/(\s*)\} as const;/;if(!o.match(p))throw new Error("Could not find closing brace of AppApis object");let v=o.lastIndexOf("} as const;"),S=o.substring(0,v),w=o.substring(v),T=S.trim().endsWith(","),_=S.match(/:\s*\{[^}]*\},\s*$/),I;_||T?I=`${S}
223
223
  ${c}
224
- ${T}`:I=C.trimEnd()+`
224
+ ${w}`:I=S.trimEnd()+`
225
225
  `+c+`
226
- `+T,await Wt(s,I)}catch(i){throw new Error(`Failed to register API endpoints: ${i}`)}};var ke=t=>{t.command("feature [name]").description("Generate a new feature module").option("--skip-store","Skip Redux store generation").option("--store <type>","Generate Redux store with persistence option (persist|no-persist)").option("--skip-service","Skip API service generation").option("--service <client>","Generate API service with specific HTTP client (axios|fetch)").option("--path <path>","Custom path for feature generation (default: src/features)").action(async(e,r)=>{try{let o=process.cwd();r.store&&!["persist","no-persist"].includes(r.store)&&(P("Invalid --store option. Use: persist or no-persist"),process.exit(1)),r.service&&!["axios","fetch"].includes(r.service)&&(P("Invalid --service option. Use: axios or fetch"),process.exit(1)),r.skipStore&&r.store&&(P("Cannot use --skip-store and --store together"),process.exit(1)),r.skipService&&r.service&&(P("Cannot use --skip-service and --service together"),process.exit(1)),p(E.cyan(`
226
+ `+w,await Pr(s,I)}catch(o){throw new Error(`Failed to register API endpoints: ${o}`)}};var ze=t=>{t.command("feature [name]").description("Generate a new feature module").option("--skip-store","Skip Redux store generation").option("--store <type>","Generate Redux store with persistence option (persist|no-persist)").option("--skip-service","Skip API service generation").option("--service <client>","Generate API service with specific HTTP client (axios|fetch)").option("--path <path>","Custom path for feature generation (default: src/features)").action(async(r,e)=>{try{let i=process.cwd();e.store&&!["persist","no-persist"].includes(e.store)&&(C("Invalid --store option. Use: persist or no-persist"),process.exit(1)),e.service&&!["axios","fetch"].includes(e.service)&&(C("Invalid --service option. Use: axios or fetch"),process.exit(1)),e.skipStore&&e.store&&(C("Cannot use --skip-store and --store together"),process.exit(1)),e.skipService&&e.service&&(C("Cannot use --skip-service and --service together"),process.exit(1)),l(E.cyan(`
227
227
  \u{1F3AF} Feature Generator
228
- `)),h.start("Detecting project setup...");let s=await z(o);h.succeed("Project setup detected"),p(E.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),p(E.dim(` HTTP Client: ${s.httpClient}`)),p(E.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
229
- `));let i=await Ne(e,s.hasRedux,s.httpClient,r.skipStore,r.store,r.skipService,r.service),n=r.path||le.join("src","features"),c=le.join(o,n,i.featureName);await $e(o,i.featureName,n)&&(P(`Feature '${i.featureName}' already exists at ${n}!`),process.exit(1)),h.start("Generating feature files..."),await Oe({featureName:i.featureName,featurePath:c,createStore:i.createStore,persistStore:i.persistStore,createService:i.createService,httpClient:i.selectedHttpClient}),h.succeed("Feature files generated"),i.createService&&(h.start("Registering API endpoints..."),await ee({serviceName:i.featureName,projectPath:o}),h.succeed("API endpoints registered")),i.createStore&&s.hasRedux&&(h.start("Registering feature in rootReducer..."),await je(o,i.featureName,i.persistStore,n),h.succeed("Feature registered in rootReducer"));let g=le.join(n,i.featureName);p(E.green(`
230
- \u2728 Feature '${i.featureName}' created successfully!
231
- `)),p(E.dim("Generated files:")),p(E.dim(` \u{1F4C2} ${g}/`)),p(E.dim(" \u251C\u2500\u2500 components/")),p(E.dim(" \u251C\u2500\u2500 hooks/")),p(E.dim(" \u251C\u2500\u2500 types/")),i.createStore&&p(E.dim(" \u251C\u2500\u2500 store/")),i.createService&&p(E.dim(" \u251C\u2500\u2500 services/")),p(E.dim(` \u2514\u2500\u2500 index.ts
232
- `)),p(E.cyan("Next steps:"));let R=n.replace(/^src\//,"@/");p(E.dim(` 1. Import and use the feature: import { ${i.featureName} } from '${R}/${i.featureName}'`)),i.createStore&&p(E.dim(` 2. Customize your Redux slice in: ${g}/store/`)),i.createService&&p(E.dim(` 3. Add API methods in: ${g}/services/${i.featureName}.service.ts`)),p("")}catch(o){h.fail("Feature generation failed"),P(`${o}`),process.exit(1)}})};import $ from"picocolors";import M from"node:path";import{existsSync as ir}from"node:fs";import{mkdir as or}from"node:fs/promises";import Jt from"enquirer";var{prompt:Kt}=Jt,De=async(t,e,r)=>{let o=[];t||o.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:i=>/^[a-z0-9-]+$/.test(i)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),e===void 0&&r===void 0&&o.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=o.length>0?await Kt(o):{};return{sliceName:t||s.sliceName,persistSlice:e===!0?!0:r===!1?!1:s.persistSlice||!1}};import{writeFile as K,mkdir as Bt}from"node:fs/promises";import B from"node:path";var Fe=async t=>{let{sliceName:e,slicePath:r,persistSlice:o}=t;await Bt(r,{recursive:!0});let s=L(e),i=O(e);await qt(e,r,s),await Zt(e,r,s,i),await Qt(e,r,s,i),o&&await er(e,r,s,i),await tr(e,r,o)},qt=async(t,e,r)=>{let o=`export interface ${r}State {
228
+ `)),x.start("Detecting project setup...");let s=await K(i);x.succeed("Project setup detected"),l(E.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),l(E.dim(` HTTP Client: ${s.httpClient}`)),l(E.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
229
+ `));let o=await De(r,s.hasRedux,s.httpClient,e.skipStore,e.store,e.skipService,e.service),n=e.path||Pe.join("src","features"),c=Pe.join(i,n,o.featureName);await Le(i,o.featureName,n)&&(C(`Feature '${o.featureName}' already exists at ${n}!`),process.exit(1)),x.start("Generating feature files..."),await Ge({featureName:o.featureName,featurePath:c,createStore:o.createStore,persistStore:o.persistStore,createService:o.createService,httpClient:o.selectedHttpClient}),x.succeed("Feature files generated"),o.createService&&(x.start("Registering API endpoints..."),await se({serviceName:o.featureName,projectPath:i}),x.succeed("API endpoints registered")),o.createStore&&s.hasRedux&&(x.start("Registering feature in rootReducer..."),await Ue(i,o.featureName,o.persistStore,n),x.succeed("Feature registered in rootReducer"));let g=Pe.join(n,o.featureName);l(E.green(`
230
+ \u2728 Feature '${o.featureName}' created successfully!
231
+ `)),l(E.dim("Generated files:")),l(E.dim(` \u{1F4C2} ${g}/`)),l(E.dim(" \u251C\u2500\u2500 components/")),l(E.dim(" \u251C\u2500\u2500 hooks/")),l(E.dim(" \u251C\u2500\u2500 types/")),o.createStore&&l(E.dim(" \u251C\u2500\u2500 store/")),o.createService&&l(E.dim(" \u251C\u2500\u2500 services/")),l(E.dim(` \u2514\u2500\u2500 index.ts
232
+ `)),l(E.cyan("Next steps:"));let v=n.replace(/^src\//,"@/");l(E.dim(` 1. Import and use the feature: import { ${o.featureName} } from '${v}/${o.featureName}'`)),o.createStore&&l(E.dim(` 2. Customize your Redux slice in: ${g}/store/`)),o.createService&&l(E.dim(` 3. Add API methods in: ${g}/services/${o.featureName}.service.ts`)),l("")}catch(i){x.fail("Feature generation failed"),C(`${i}`),process.exit(1)}})};import $ from"picocolors";import X from"node:path";import{existsSync as Or}from"node:fs";import{mkdir as $r}from"node:fs/promises";import yr from"enquirer";var{prompt:vr}=yr,Je=async(t,r,e)=>{let i=[];t||i.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:o=>/^[a-z0-9-]+$/.test(o)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),r===void 0&&e===void 0&&i.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=i.length>0?await vr(i):{};return{sliceName:t||s.sliceName,persistSlice:r===!0?!0:e===!1?!1:s.persistSlice||!1}};import{writeFile as te,mkdir as Cr}from"node:fs/promises";import re from"node:path";var Ye=async t=>{let{sliceName:r,slicePath:e,persistSlice:i}=t;await Cr(e,{recursive:!0});let s=H(r),o=A(r);await wr(r,e,s),await Tr(r,e,s,o),await Er(r,e,s,o),i&&await Rr(r,e,s,o),await Ir(r,e,i)},wr=async(t,r,e)=>{let i=`export interface ${e}State {
233
233
  loading: boolean;
234
234
  error: string | null;
235
235
  // Add your state properties here
236
236
  }
237
- `;await K(B.join(e,`${t}.types.ts`),o)},Zt=async(t,e,r,o)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
238
- import { ${r}State } from './${t}.types';
237
+ `;await te(re.join(r,`${t}.types.ts`),i)},Tr=async(t,r,e,i)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
238
+ import { ${e}State } from './${t}.types';
239
239
 
240
- const initialState: ${r}State = {
240
+ const initialState: ${e}State = {
241
241
  loading: false,
242
242
  error: null,
243
243
  // Add your initial state here
244
244
  };
245
245
 
246
- export const ${o}Slice = createSlice({
247
- name: '${o}',
246
+ export const ${i}Slice = createSlice({
247
+ name: '${i}',
248
248
  initialState,
249
249
  reducers: {
250
250
  setLoading: (state, action: PayloadAction<boolean>) => {
@@ -260,35 +260,35 @@ export const ${o}Slice = createSlice({
260
260
  },
261
261
  });
262
262
 
263
- export const { setLoading, setError, resetState } = ${o}Slice.actions;
263
+ export const { setLoading, setError, resetState } = ${i}Slice.actions;
264
264
 
265
- export const ${o}Reducer = ${o}Slice.reducer;
266
- `;await K(B.join(e,`${t}.slice.ts`),s)},Qt=async(t,e,r,o)=>{let s=`import { RootState } from '@/store/rootReducer';
265
+ export const ${i}Reducer = ${i}Slice.reducer;
266
+ `;await te(re.join(r,`${t}.slice.ts`),s)},Er=async(t,r,e,i)=>{let s=`import { RootState } from '@/store/rootReducer';
267
267
 
268
- export const select${r}State = (state: RootState) => state.${o};
268
+ export const select${e}State = (state: RootState) => state.${i};
269
269
  export { setLoading, setError, resetState } from './${t}.slice';
270
- `;await K(B.join(e,`${t}.selectors.ts`),s)},er=async(t,e,r,o)=>{let s=`import { PersistConfig } from 'redux-persist';
270
+ `;await te(re.join(r,`${t}.selectors.ts`),s)},Rr=async(t,r,e,i)=>{let s=`import { PersistConfig } from 'redux-persist';
271
271
  import storage from 'redux-persist/lib/storage';
272
- import { ${r}State } from './${t}.types';
272
+ import { ${e}State } from './${t}.types';
273
273
 
274
- export const ${o}PersistConfig: PersistConfig<${r}State> = {
275
- key: '${o}',
274
+ export const ${i}PersistConfig: PersistConfig<${e}State> = {
275
+ key: '${i}',
276
276
  storage,
277
277
  // whitelist: ['someField'], // Specify which fields to persist
278
278
  };
279
- `;await K(B.join(e,"persist.ts"),s)},tr=async(t,e,r)=>{let o=`export * from './${t}.slice';
279
+ `;await te(re.join(r,"persist.ts"),s)},Ir=async(t,r,e)=>{let i=`export * from './${t}.slice';
280
280
  export * from './${t}.selectors';
281
- export * from './${t}.types';${r?`
281
+ export * from './${t}.types';${e?`
282
282
  export * from './persist';`:""}
283
- `;await K(B.join(e,"index.ts"),o)};import{access as rr}from"node:fs/promises";import Le from"node:path";var Ge=async(t,e,r=Le.join("src","store","slices"))=>{let o=Le.join(t,r,e);try{return await rr(o),!0}catch{return!1}};var Me=t=>{t.command("slice [name]").description("Generate a Redux slice").option("--path <path>","Custom path for slice generation (default: create new feature)").option("--persist","Enable persistence for this slice").option("--no-persist","Disable persistence for this slice").action(async(e,r)=>{try{let o=process.cwd();r.persist&&r.noPersist===!0&&(P("Cannot use --persist and --no-persist together"),process.exit(1)),p($.cyan(`
283
+ `;await te(re.join(r,"index.ts"),i)};import{access as Nr}from"node:fs/promises";import Ve from"node:path";var We=async(t,r,e=Ve.join("src","store","slices"))=>{let i=Ve.join(t,e,r);try{return await Nr(i),!0}catch{return!1}};var Be=t=>{t.command("slice [name]").description("Generate a Redux slice").option("--path <path>","Custom path for slice generation (default: create new feature)").option("--persist","Enable persistence for this slice").option("--no-persist","Disable persistence for this slice").action(async(r,e)=>{try{let i=process.cwd();e.persist&&e.noPersist===!0&&(C("Cannot use --persist and --no-persist together"),process.exit(1)),l($.cyan(`
284
284
  \u{1F527} Slice Generator
285
- `)),h.start("Detecting project setup...");let s=await z(o);h.succeed("Project setup detected"),s.hasRedux||(h.fail("Redux is not setup in this project"),P("Please install @reduxjs/toolkit and react-redux first"),p($.dim(`
285
+ `)),x.start("Detecting project setup...");let s=await K(i);x.succeed("Project setup detected"),s.hasRedux||(x.fail("Redux is not setup in this project"),C("Please install @reduxjs/toolkit and react-redux first"),l($.dim(`
286
286
  Run: npm install @reduxjs/toolkit react-redux
287
- `)),process.exit(1)),p($.dim(` Redux: \u2713
288
- `));let i=await De(e,r.persist,r.noPersist===!0?!1:void 0),n,c,l;if(r.path){let v=r.path.replace(/^src\//,"");v.startsWith("features/")?(c=v.split("/")[1],n=M.join("src","features",c,"store"),l=M.join(o,n,i.sliceName)):(n=M.join("src",v),c=v.split("/")[0],l=M.join(o,n,i.sliceName))}else c=i.sliceName,n=M.join("src","features",c,"store"),l=M.join(o,n,i.sliceName);let g=M.join(o,n);ir(g)||await or(g,{recursive:!0}),await Ge(o,i.sliceName,n)&&(P(`Slice '${i.sliceName}' already exists at ${n}!`),process.exit(1)),h.start("Generating slice files..."),await Fe({sliceName:i.sliceName,slicePath:l,persistSlice:i.persistSlice}),h.succeed("Slice files generated"),h.start("Registering slice in rootReducer..."),await _e(o,i.sliceName,i.persistSlice,n),h.succeed("Slice registered in rootReducer");let C=M.join(n,i.sliceName);p($.green(`
289
- \u2728 Slice '${i.sliceName}' created successfully!
290
- `)),p($.dim("Generated files:")),p($.dim(` \u{1F4C2} ${C}/`)),p($.dim(` \u251C\u2500\u2500 ${i.sliceName}.slice.ts`)),p($.dim(` \u251C\u2500\u2500 ${i.sliceName}.selectors.ts`)),i.persistSlice&&p($.dim(" \u251C\u2500\u2500 persist.ts")),p($.dim(` \u251C\u2500\u2500 ${i.sliceName}.types.ts`)),p($.dim(` \u2514\u2500\u2500 index.ts
291
- `)),p($.cyan("Next steps:"));let T=n.replace(/^src\//,"@/");p($.dim(` 1. Import actions: import { setLoading, setError } from '${T}/${i.sliceName}'`)),p($.dim(" 2. Use in component: dispatch(setLoading(true))")),p("")}catch(o){h.fail("Slice generation failed"),P(`${o}`),process.exit(1)}})};import F from"picocolors";import X from"node:path";import{existsSync as lr}from"node:fs";import{mkdir as mr}from"node:fs/promises";import Ue from"enquirer";var He=async(t,e,r,o)=>{let s=t||(await Ue.prompt({type:"input",name:"serviceName",message:"Service name (kebab-case):",validate:n=>n?/^[a-z0-9-]+$/.test(n)?!0:"Service name must be lowercase with hyphens only":"Service name is required"})).serviceName,i;return e!==void 0?i="axios":r!==void 0?i="fetch":o==="axios"?i="axios":o==="fetch"?i="fetch":o==="both"?i=(await Ue.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:i="axios",{serviceName:s,httpClient:i}};import{writeFile as nr}from"node:fs/promises";import sr from"node:path";var Xe=async t=>{await ar(t)},ar=async t=>{let{serviceName:e,servicePath:r,httpClient:o}=t,s=O(e),i;o==="axios"?i=`import { AppApis } from '@/lib/config';
287
+ `)),process.exit(1)),l($.dim(` Redux: \u2713
288
+ `));let o=await Je(r,e.persist,e.noPersist===!0?!1:void 0),n,c,p;if(e.path){let T=e.path.replace(/^src\//,"");T.startsWith("features/")?(c=T.split("/")[1],n=X.join("src","features",c,"store"),p=X.join(i,n,o.sliceName)):(n=X.join("src",T),c=T.split("/")[0],p=X.join(i,n,o.sliceName))}else c=o.sliceName,n=X.join("src","features",c,"store"),p=X.join(i,n,o.sliceName);let g=X.join(i,n);Or(g)||await $r(g,{recursive:!0}),await We(i,o.sliceName,n)&&(C(`Slice '${o.sliceName}' already exists at ${n}!`),process.exit(1)),x.start("Generating slice files..."),await Ye({sliceName:o.sliceName,slicePath:p,persistSlice:o.persistSlice}),x.succeed("Slice files generated"),x.start("Registering slice in rootReducer..."),await Xe(i,o.sliceName,o.persistSlice,n),x.succeed("Slice registered in rootReducer");let S=X.join(n,o.sliceName);l($.green(`
289
+ \u2728 Slice '${o.sliceName}' created successfully!
290
+ `)),l($.dim("Generated files:")),l($.dim(` \u{1F4C2} ${S}/`)),l($.dim(` \u251C\u2500\u2500 ${o.sliceName}.slice.ts`)),l($.dim(` \u251C\u2500\u2500 ${o.sliceName}.selectors.ts`)),o.persistSlice&&l($.dim(" \u251C\u2500\u2500 persist.ts")),l($.dim(` \u251C\u2500\u2500 ${o.sliceName}.types.ts`)),l($.dim(` \u2514\u2500\u2500 index.ts
291
+ `)),l($.cyan("Next steps:"));let w=n.replace(/^src\//,"@/");l($.dim(` 1. Import actions: import { setLoading, setError } from '${w}/${o.sliceName}'`)),l($.dim(" 2. Use in component: dispatch(setLoading(true))")),l("")}catch(i){x.fail("Slice generation failed"),C(`${i}`),process.exit(1)}})};import L from"picocolors";import W from"node:path";import{existsSync as Fr}from"node:fs";import{mkdir as Dr}from"node:fs/promises";import Ke from"enquirer";var qe=async(t,r,e,i)=>{let s=t||(await Ke.prompt({type:"input",name:"serviceName",message:"Service name (kebab-case):",validate:n=>n?/^[a-z0-9-]+$/.test(n)?!0:"Service name must be lowercase with hyphens only":"Service name is required"})).serviceName,o;return r!==void 0?o="axios":e!==void 0?o="fetch":i==="axios"?o="axios":i==="fetch"?o="fetch":i==="both"?o=(await Ke.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:o="axios",{serviceName:s,httpClient:o}};import{writeFile as Ar}from"node:fs/promises";import br from"node:path";var Ze=async t=>{await _r(t)},_r=async t=>{let{serviceName:r,servicePath:e,httpClient:i}=t,s=A(r),o;i==="axios"?o=`import { AppApis } from '@/lib/config';
292
292
  import { axiosClient } from '@/lib/utils/http';
293
293
  import { ResultAsync } from '@/types';
294
294
 
@@ -297,7 +297,7 @@ export const ${s}Service = {
297
297
  return axiosClient.get<string>(AppApis.${s}.getAll);
298
298
  },
299
299
  };
300
- `:i=`import { AppApis } from '@/lib/config';
300
+ `:o=`import { AppApis } from '@/lib/config';
301
301
  import { fetchClient } from '@/lib/utils/http';
302
302
  import { ResultAsync } from '@/types';
303
303
 
@@ -306,27 +306,27 @@ export const ${s}Service = {
306
306
  return fetchClient.get<string>(AppApis.${s}.getAll);
307
307
  },
308
308
  };
309
- `;let n=`${e}.service.ts`;await nr(sr.join(r,n),i)};import{existsSync as cr}from"node:fs";import pr from"node:path";var ze=async(t,e,r)=>{let o=pr.join(t,r,`${e}.service.ts`);return cr(o)};var Ye=t=>{t.command("service [name]").description("Generate an API service").option("--path <path>","Custom path for service generation (default: create new feature)").option("--axios","Use Axios HTTP client").option("--fetch","Use Fetch HTTP client").action(async(e,r)=>{try{let o=process.cwd();r.axios&&r.fetch&&(P("Cannot use --axios and --fetch together"),process.exit(1)),p(F.cyan(`
309
+ `;let n=`${r}.service.ts`;await Ar(br.join(e,n),o)};import{existsSync as jr}from"node:fs";import kr from"node:path";var Qe=async(t,r,e)=>{let i=kr.join(t,e,`${r}.service.ts`);return jr(i)};var et=t=>{t.command("service [name]").description("Generate an API service").option("--path <path>","Custom path for service generation (default: create new feature)").option("--axios","Use Axios HTTP client").option("--fetch","Use Fetch HTTP client").action(async(r,e)=>{try{let i=process.cwd();e.axios&&e.fetch&&(C("Cannot use --axios and --fetch together"),process.exit(1)),l(L.cyan(`
310
310
  \u{1F527} Service Generator
311
- `)),h.start("Detecting project setup...");let s=await z(o);h.succeed("Project setup detected"),s.httpClient==="none"&&(h.fail("No HTTP client is setup in this project"),P("Please setup either AxiosClient or FetchClient first"),p(F.dim(`
311
+ `)),x.start("Detecting project setup...");let s=await K(i);x.succeed("Project setup detected"),s.httpClient==="none"&&(x.fail("No HTTP client is setup in this project"),C("Please setup either AxiosClient or FetchClient first"),l(L.dim(`
312
312
  Check: lib/utils/http/axios-client or lib/utils/http/fetch-client
313
- `)),process.exit(1));let i=[];(s.httpClient==="axios"||s.httpClient==="both")&&i.push("Axios \u2713"),(s.httpClient==="fetch"||s.httpClient==="both")&&i.push("Fetch \u2713"),p(F.dim(` HTTP Clients: ${i.join(", ")}
314
- `));let n=await He(e,r.axios,r.fetch,s.httpClient),c,l,g;if(r.path){let v=r.path.replace(/^src\//,"");v.startsWith("features/")?(l=v.split("/")[1],c=X.join("src","features",l,"services"),g=X.join(o,c)):(c=X.join("src",v),l=v.split("/")[0],g=X.join(o,c))}else l=n.serviceName,c=X.join("src","features",l,"services"),g=X.join(o,c);lr(g)||await mr(g,{recursive:!0}),await ze(o,n.serviceName,c)&&(P(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),h.start("Generating service files..."),await Xe({serviceName:n.serviceName,servicePath:g,httpClient:n.httpClient}),h.succeed("Service files generated"),h.start("Registering API endpoints..."),await ee({serviceName:n.serviceName,projectPath:o}),h.succeed("API endpoints registered");let C=X.join(c,`${n.serviceName}.service.ts`);p(F.green(`
313
+ `)),process.exit(1));let o=[];(s.httpClient==="axios"||s.httpClient==="both")&&o.push("Axios \u2713"),(s.httpClient==="fetch"||s.httpClient==="both")&&o.push("Fetch \u2713"),l(L.dim(` HTTP Clients: ${o.join(", ")}
314
+ `));let n=await qe(r,e.axios,e.fetch,s.httpClient),c,p,g;if(e.path){let T=e.path.replace(/^src\//,"");T.startsWith("features/")?(p=T.split("/")[1],c=W.join("src","features",p,"services"),g=W.join(i,c)):(c=W.join("src",T),p=T.split("/")[0],g=W.join(i,c))}else p=n.serviceName,c=W.join("src","features",p,"services"),g=W.join(i,c);Fr(g)||await Dr(g,{recursive:!0}),await Qe(i,n.serviceName,c)&&(C(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),x.start("Generating service files..."),await Ze({serviceName:n.serviceName,servicePath:g,httpClient:n.httpClient}),x.succeed("Service files generated"),x.start("Registering API endpoints..."),await se({serviceName:n.serviceName,projectPath:i}),x.succeed("API endpoints registered");let S=W.join(c,`${n.serviceName}.service.ts`);l(L.green(`
315
315
  \u2728 Service '${n.serviceName}' created successfully!
316
- `)),p(F.dim("Generated files:")),p(F.dim(` \u{1F4C4} ${C}
317
- `)),p(F.cyan("Next steps:"));let T=c.replace(/^src\//,"@/");p(F.dim(` 1. Import service: import { ${n.serviceName}Service } from '${T}/${n.serviceName}.service'`)),p(F.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),p("")}catch(o){h.fail("Service generation failed"),P(`${o}`),process.exit(1)}})};import j from"picocolors";import gr from"enquirer";import ur from"node:path";import fr from"picocolors";import q from"node:path";import We from"node:path";var Ve=async t=>{let e=[We.join(t,a.ROOT_LAYOUT),We.join(t,"src/app/[locale]/layout.tsx")];for(let r of e)if(f(r)&&(await d(r)).includes("<body"))return r;for(let r of e)if(f(r))return r;return""};var Je=async t=>{let e=q.join(t,a.THEME_PROVIDER),r=q.join(t,a.GLOBALS_CSS),o=q.join(t,"package.json");if(f(e))return{isSetup:!0,reason:"CustomThemeProvider.tsx exists"};if(f(o)){let s=JSON.parse(await d(o));if(s.dependencies&&s.dependencies["next-themes"]||s.devDependencies&&s.devDependencies["next-themes"])return{isSetup:!0,reason:"next-themes is installed"}}return f(r)&&(await d(r)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},Ke=async t=>{let e=q.join(t,a.GLOBALS_CSS),r=q.join(t,a.PROVIDERS_INDEX),o=await Ve(t);if(!f(e)||!o||!f(r))throw new Error("Project structure mismatch. Ensure src/styles/globals.css, src/app/layout.tsx (or src/app/[locale]/layout.tsx), and src/providers/index.ts exist.");return o};import Be from"node:path";import dr from"degit";var qe=async(t,e)=>{e.text="Fetching assets from starter repo...",await dr("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},Ze=async(t,e)=>{let r=Be.join(t,a.THEME_PROVIDER),o=Be.join(e,"src/providers/CustomThemeProvider.tsx");await fe(o,r)};import te from"node:path";var Qe=async t=>{let e=te.join(t,a.PROVIDERS_INDEX),r=await d(e);r.includes("CustomThemeProvider")||(r+=`export * from './CustomThemeProvider';
318
- `,await u(e,r))},et=async t=>{let e=te.join(t,"src/providers/RootProvider.tsx");if(f(e)){let r=await d(e);r.includes("CustomThemeProvider")||(r=r.replace(/import \{ StoreProvider \} from '@\/providers';\n/,`import { StoreProvider, CustomThemeProvider } from '@/providers';
319
- `),r.includes("CustomThemeProvider")||(r.includes("from '@/providers'")?r=r.replace(/\} from '@\/providers'/,", CustomThemeProvider } from '@/providers'"):r=`import { CustomThemeProvider } from '@/providers';
320
- `+r)),r.includes("<CustomThemeProvider>")||(r.includes("<StoreProvider>")?(r=r.replace(/<StoreProvider>/,`<StoreProvider>
321
- <CustomThemeProvider>`),r=r.replace(/<\/StoreProvider>/,`</CustomThemeProvider>
322
- </StoreProvider>`)):r.match(/return \(\s*([\s\S]*?)\s*\);/)&&(r=r.replace(/return \(\s*<([^>]+)([^>]*)>([\s\S]*)<\/\1>\s*\);/,(s,i,n,c)=>`return (
316
+ `)),l(L.dim("Generated files:")),l(L.dim(` \u{1F4C4} ${S}
317
+ `)),l(L.cyan("Next steps:"));let w=c.replace(/^src\//,"@/");l(L.dim(` 1. Import service: import { ${n.serviceName}Service } from '${w}/${n.serviceName}.service'`)),l(L.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),l("")}catch(i){x.fail("Service generation failed"),C(`${i}`),process.exit(1)}})};import q from"picocolors";import Br from"enquirer";import Gr from"node:path";import Mr from"picocolors";import oe from"node:path";import tt from"node:path";var ae=async t=>{let r=[tt.join(t,a.ROOT_LAYOUT),tt.join(t,"src/app/[locale]/layout.tsx")];for(let e of r)if(m(e)&&(await d(e)).includes("<body"))return e;for(let e of r)if(m(e))return e;return""};var rt=async t=>{let r=oe.join(t,a.THEME_PROVIDER),e=oe.join(t,a.GLOBALS_CSS),i=oe.join(t,"package.json");if(m(r))return{isSetup:!0,reason:"CustomThemeProvider.tsx exists"};if(m(i)){let s=JSON.parse(await d(i));if(s.dependencies&&s.dependencies["next-themes"]||s.devDependencies&&s.devDependencies["next-themes"])return{isSetup:!0,reason:"next-themes is installed"}}return m(e)&&(await d(e)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},ot=async t=>{let r=oe.join(t,a.GLOBALS_CSS),e=oe.join(t,a.PROVIDERS_INDEX),i=await ae(t);if(!m(r)||!i||!m(e))throw new Error("Project structure mismatch. Ensure src/styles/globals.css, src/app/layout.tsx (or src/app/[locale]/layout.tsx), and src/providers/index.ts exist.");return i};import it from"node:path";import Lr from"degit";var nt=async(t,r)=>{r.text="Fetching assets from starter repo...",await Lr("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},st=async(t,r)=>{let e=it.join(t,a.THEME_PROVIDER),i=it.join(r,"src/providers/CustomThemeProvider.tsx");await M(i,e)};import ce from"node:path";var at=async t=>{let r=ce.join(t,a.PROVIDERS_INDEX),e=await d(r);e.includes("CustomThemeProvider")||(e+=`export * from './CustomThemeProvider';
318
+ `,await u(r,e))},ct=async t=>{let r=ce.join(t,"src/providers/RootProvider.tsx");if(m(r)){let e=await d(r);e.includes("CustomThemeProvider")||(e=e.replace(/import \{ StoreProvider \} from '@\/providers';\n/,`import { StoreProvider, CustomThemeProvider } from '@/providers';
319
+ `),e.includes("CustomThemeProvider")||(e.includes("from '@/providers'")?e=e.replace(/\} from '@\/providers'/,", CustomThemeProvider } from '@/providers'"):e=`import { CustomThemeProvider } from '@/providers';
320
+ `+e)),e.includes("<CustomThemeProvider>")||(e.includes("<StoreProvider>")?(e=e.replace(/<StoreProvider>/,`<StoreProvider>
321
+ <CustomThemeProvider>`),e=e.replace(/<\/StoreProvider>/,`</CustomThemeProvider>
322
+ </StoreProvider>`)):e.match(/return \(\s*([\s\S]*?)\s*\);/)&&(e=e.replace(/return \(\s*<([^>]+)([^>]*)>([\s\S]*)<\/\1>\s*\);/,(s,o,n,c)=>`return (
323
323
  <CustomThemeProvider>
324
- <${i}${n}>${c}</${i}>
324
+ <${o}${n}>${c}</${o}>
325
325
  </CustomThemeProvider>
326
- );`)),await u(e,r))}},tt=async(t,e)=>{let r=te.join(t,a.GLOBALS_CSS),o=te.join(e,"src/styles/globals.css"),s="";if(f(o)){let n=await d(o),c=n.match(/@custom-variant dark \(.*?\);/),l=n.match(/@theme \{[\s\S]*?\}/);c&&(s+=`
326
+ );`)),await u(r,e))}},lt=async(t,r)=>{let e=ce.join(t,a.GLOBALS_CSS),i=ce.join(r,"src/styles/globals.css"),s="";if(m(i)){let n=await d(i),c=n.match(/@custom-variant dark \(.*?\);/),p=n.match(/@theme \{[\s\S]*?\}/);c&&(s+=`
327
327
  ${c[0]}
328
- `),l&&(s+=`
329
- ${l[0]}
328
+ `),p&&(s+=`
329
+ ${p[0]}
330
330
  `)}s||(s=`
331
331
  @custom-variant dark (&:where(.dark, .dark *));
332
332
 
@@ -334,12 +334,73 @@ ${l[0]}
334
334
  --color-dark: #202938;
335
335
  --color-light: #f5f5f5;
336
336
  }
337
- `);let i=await d(r);if(!i.includes("@custom-variant dark")){if(i.includes("@import")){let n=i.lastIndexOf("@import"),c=i.indexOf(`
338
- `,n);i=i.slice(0,c+1)+s+i.slice(c+1)}else i=s+i;await u(r,i)}},rt=async t=>{let e=await d(t);e.includes("dark:bg-dark")||(e=e.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await u(t,e))};var me=async t=>{let e=b("Setting up Dark Theme..."),r=ur.join(t,".next-maker-temp");try{let{isSetup:o,reason:s}=await Je(t);if(o){e.fail(`Dark Theme is already set up (${s}).`);return}let i=await Ke(t);await qe(r,e),await Ze(t,r),await Qe(t),await et(t),await tt(t,r),await rt(i),e.text="Installing next-themes...",await xe(t,"next-themes"),e.text="Formatting code...";let n=await ne(t);await W(t,n,"format"),e.succeed(fr.green("Dark Theme setup successfully!"))}catch(o){throw e.fail("Failed to setup Dark Theme."),o}finally{await S(r)}};var{prompt:hr}=gr,it=t=>{t.command("setup").description("Setup additional features for your Next.js project").option("--http-client <type>","Setup HTTP client (axios|fetch|both)").option("--dark-theme","Setup dark theme support").option("--redux","Setup Redux Toolkit with persistence").option("--i18n","Setup next-intl for internationalization").action(async e=>{try{if(p(j.cyan(`
337
+ `);let o=await d(e);if(!o.includes("@custom-variant dark")){if(o.includes("@import")){let n=o.lastIndexOf("@import"),c=o.indexOf(`
338
+ `,n);o=o.slice(0,c+1)+s+o.slice(c+1)}else o=s+o;await u(e,o)}},pt=async t=>{let r=await d(t);r.includes("dark:bg-dark")||(r=r.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await u(t,r))};var Se=async t=>{let r=N("Setting up Dark Theme..."),e=Gr.join(t,".next-maker-temp");try{let{isSetup:i,reason:s}=await rt(t);if(i){r.fail(`Dark Theme is already set up (${s}).`);return}let o=await ot(t);await nt(e,r),await st(t,e),await at(t),await ct(t),await lt(t,e),await pt(o),r.text="Installing next-themes...",await F(t,"next-themes"),r.text="Formatting code...";let n=await Y(t);await k(t,n,"format"),r.succeed(Mr.green("Dark Theme setup successfully!"))}catch(i){throw r.fail("Failed to setup Dark Theme."),i}finally{await P(e)}};import Ur from"node:path";import Xr from"picocolors";import ye from"node:path";var mt=async t=>{let r=ye.join(t,a.STORE),e=ye.join(t,"package.json");if(m(r))return{isSetup:!0,reason:"src/store directory exists"};if(m(e)){let i=JSON.parse(await d(e));if(i.dependencies&&i.dependencies["@reduxjs/toolkit"]||i.devDependencies&&i.devDependencies["@reduxjs/toolkit"])return{isSetup:!0,reason:"@reduxjs/toolkit is installed"}}return{isSetup:!1,reason:""}},dt=async t=>{let r=ye.join(t,a.PROVIDERS_INDEX);if(!await ae(t)||!m(r))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx (or src/app/[locale]/layout.tsx) and src/providers/index.ts exist.")};import B from"node:path";import Hr from"degit";import ut from"node:fs/promises";var ft=async(t,r)=>{r.text="Fetching assets from starter repo...",await Hr("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},gt=async(t,r)=>{let e=B.join(r,"src/providers/StoreProvider.tsx"),i=B.join(t,a.STORE_PROVIDER);await M(e,i);let s=B.join(r,"src/store"),o=B.join(t,a.STORE);await ut.cp(s,o,{recursive:!0})},xt=async(t,r)=>{let e=B.join(r,"src/features/counter"),i=B.join(t,a.COUNTER_FEATURE);await ut.cp(e,i,{recursive:!0});let s=B.join(i,"components/Counter.tsx");if(await m(s)){let o=await d(s);o=o.replace(/import \{ useTranslations \} from 'next-intl';\n?/,""),o=o.replace(/const t = useTranslations\('Count'\);\n?/,""),o=o.replace(/\{t\('currentCount', \{ count: value \}\)\}/g,"Current Count: {value}"),o=o.replace(/\{t\('increment'\)\}/g,"Increment"),o=o.replace(/\{t\('decrement'\)\}/g,"Decrement"),o=o.replace(/\{t\('reset'\)\}/g,"Reset"),await u(s,o)}};import le from"node:path";var ht=async t=>{let r=le.join(t,a.PROVIDERS_INDEX),e=await d(r);e.includes("StoreProvider")||(e+=`export * from './StoreProvider';
339
+ `,await u(r,e))},Pt=async t=>{let r=le.join(t,"src/providers/RootProvider.tsx");if(m(r)){let e=await d(r);e.includes("StoreProvider")||(e=e.replace(/import \{ (.*?) \} from '@\/providers';/,"import { $1, StoreProvider } from '@/providers';"),e.includes("StoreProvider")||(e.includes("from '@/providers'")?e=e.replace(/\} from '@\/providers'/,", StoreProvider } from '@/providers'"):e=`import { StoreProvider } from '@/providers';
340
+ `+e)),e.includes("<StoreProvider>")||e.match(/return \(\s*([\s\S]*?)\s*\);/)&&(e=e.replace(/return \(\s*<([^>]+)([^>]*)>([\s\S]*)<\/\1>\s*\);/,(s,o,n,c)=>`return (
341
+ <StoreProvider>
342
+ <${o}${n}>${c}</${o}>
343
+ </StoreProvider>
344
+ );`),await u(r,e))}},St=async t=>{let r=[le.join(t,a.ROOT_PAGE),le.join(t,"src/app/[locale]/page.tsx")],e="";for(let i of r)if(m(i)){e=i;break}if(e){let i=await d(e);if(i.includes("Counter")||(i=`import { Counter } from '@/features/counter/components/Counter';
345
+ `+i),!i.includes("<Counter />")){let s=i.lastIndexOf("</div>"),o=i.lastIndexOf("</main>"),n=o!==-1?o:s;n!==-1&&(i=i.slice(0,n)+`
346
+ <div className="mt-8">
347
+ <h2 className="text-2xl font-bold mb-4">Redux Counter</h2>
348
+ <Counter />
349
+ </div>
350
+ `+i.slice(n),await u(e,i))}}};var ve=async t=>{let r=N("Setting up Redux Toolkit..."),e=Ur.join(t,".next-maker-temp-redux");try{let{isSetup:i,reason:s}=await mt(t);if(i){r.fail(`Redux is already set up (${s}).`);return}await dt(t),await ft(e,r),r.text="Copying Redux files...",await gt(t,e),r.text="Creating Counter feature...",await xt(t,e),r.text="Updating providers and pages...",await ht(t),await Pt(t),await St(t),r.text="Installing dependencies...",await F(t,"@reduxjs/toolkit"),await F(t,"react-redux"),await F(t,"redux-persist"),await F(t,"react-secure-storage"),r.text="Formatting code...";let o=await Y(t);await k(t,o,"format"),r.succeed(Xr.green("Redux Toolkit setup successfully!"))}catch(i){throw r.fail("Failed to setup Redux Toolkit."),i}finally{await P(e)}};import Vr from"node:path";import Wr from"picocolors";import pe from"node:path";var yt=async t=>{let r=pe.join(t,a.I18N_DIR),e=pe.join(t,"package.json");if(m(r))return{isSetup:!0,reason:"src/i18n directory exists"};if(m(e)){let i=JSON.parse(await d(e));if(i.dependencies&&i.dependencies["next-intl"]||i.devDependencies&&i.devDependencies["next-intl"])return{isSetup:!0,reason:"next-intl is installed"}}return{isSetup:!1,reason:""}},vt=async t=>{let r=pe.join(t,a.ROOT_LAYOUT),e=pe.join(t,"src/app/[locale]/layout.tsx");if(!m(r)&&!m(e))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx exists.")};import z from"node:path";import zr from"degit";import Jr from"node:fs/promises";var Ct=async(t,r)=>{r.text="Fetching assets from starter repo...",await zr("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},wt=async(t,r)=>{let e=z.join(r,"src/i18n"),i=z.join(t,a.I18N_DIR);await Jr.cp(e,i,{recursive:!0});let s=z.join(r,"src/proxy.ts"),o=z.join(t,a.PROXY);await M(s,o);let n=z.join(r,"src/types/i18n.ts"),c=z.join(t,a.I18N_TYPES);await M(n,c);let p=z.join(r,"src/lib/config/app-locales.ts"),g=z.join(t,a.APP_LOCALES);await M(p,g)};import G from"node:path";import Yr from"node:fs/promises";var Tt=async t=>{let r=G.join(t,a.NEXT_CONFIG);if(m(r)){let e=await d(r);if(!e.includes("createNextIntlPlugin")){e=`import createNextIntlPlugin from 'next-intl/plugin';
351
+ `+e;let i=/export default (.*?);/;i.test(e)?e=e.replace(i,`
352
+ const withNextIntl = createNextIntlPlugin();
353
+ export default withNextIntl($1);`):(e+=`
354
+ const withNextIntl = createNextIntlPlugin();
355
+ `,e+=`export default withNextIntl(nextConfig);
356
+ `),await u(r,e)}}},Et=async t=>{let r=G.join(t,a.TYPES_INDEX);if(m(r)){let e=await d(r);e.includes("./i18n")||(e+=`export * from './i18n';
357
+ `,await u(r,e))}},Rt=async t=>{let r=G.join(t,a.CONFIG_INDEX);if(m(r)){let e=await d(r);e.includes("./app-locales")||(e+=`export * from './app-locales';
358
+ `,await u(r,e))}},It=async t=>{let r=G.join(t,"src/providers/RootProvider.tsx");if(m(r)){let e=await d(r),i="'use client';",s=e.includes(i);if(s&&(e=e.replace(i,"").trim()),e.includes("next-intl")||(e=`import { SupportedLocale } from '@/types/i18n';
359
+ import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';
360
+ `+e),s&&(e=i+`
361
+ `+e),!e.includes("locale: SupportedLocale")){let o=/export const RootProvider = \(\{([\s\S]*?)\}: \{([\s\S]*?)\}\) => \{/,n=e.match(o);n&&(e=e.replace(n[0],`export const RootProvider = ({
362
+ children,
363
+ locale,
364
+ messages,
365
+ }: {
366
+ children: React.ReactNode;
367
+ locale: SupportedLocale;
368
+ messages: AbstractIntlMessages;
369
+ }) => {`))}e.includes("<NextIntlClientProvider")||e.match(/return \(\s*([\s\S]*?)\s*\);/)&&(e=e.replace(/return \(\s*<([^>]+)([^>]*)>([\s\S]*)<\/\1>\s*\);/,n=>n.replace(/\{children\}/,`<NextIntlClientProvider locale={locale} messages={messages}>
370
+ {children}
371
+ </NextIntlClientProvider>`))),await u(r,e)}},Nt=async t=>{let r=G.join(t,a.ROOT_LAYOUT),e=G.join(t,a.ROOT_PAGE),i=G.join(t,"src/app/[locale]");if(await Yr.mkdir(i,{recursive:!0}),m(r)){let s=G.join(i,"layout.tsx"),o=await d(r);if(o.includes("next-intl")||(o=`import { routing } from '@/i18n/routing';
372
+ import { hasLocale } from 'next-intl';
373
+ import { notFound } from 'next/navigation';
374
+ import { setRequestLocale, getMessages } from 'next-intl/server';
375
+ `+o),!o.includes("generateStaticParams")){let p=o.indexOf("};",o.indexOf("export const metadata"));if(p!==-1){let g=p+2;o=o.slice(0,g)+`
376
+
377
+ export function generateStaticParams() {
378
+ return routing.locales.map((locale) => ({ locale }));
379
+ }`+o.slice(g)}}o=o.replace(/Readonly<\{\s*children:\s*React\.ReactNode;\s*}>/,`Readonly<{
380
+ children: React.ReactNode;
381
+ params: Promise<{ locale: string }>;
382
+ }>`);let n=/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,c=o.match(n);if(c){c[1]||(o=o.replace("export default function","export default async function")),o=o.replace(/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,"export default async function RootLayout({ children, params }:");let g=/export default async function RootLayout[\s\S]*?\)\s*\{/,v=o.match(g);if(v&&v.index!==void 0){let S=v.index+v[0].length-1;o=o.slice(0,S+1)+`
383
+ const { locale } = await params;
384
+
385
+ if (!hasLocale(routing.locales, locale)) {
386
+ notFound();
387
+ }
388
+
389
+ setRequestLocale(locale);
390
+
391
+ const messages = await getMessages();
392
+ `+o.slice(S+1)}o=o.replace(/<RootProvider>/,"<RootProvider locale={locale} messages={messages}>"),o=o.replace(/<html lang="en"/,"<html lang={locale}")}await u(s,o),await h(r)}if(m(e)){let s=G.join(i,"page.tsx"),o=await d(e);o.includes("next-intl")||(o=`import { SupportedLocale } from '@/types/i18n';
393
+ import { setRequestLocale } from 'next-intl/server';
394
+ `+o),o=o.replace(/export default function Home\(\)/,`type Props = {
395
+ params: Promise<{ locale: string }>;
396
+ };
397
+
398
+ export default async function Home(props: Props)`);let n=o.indexOf("export default async function Home(props: Props) {");if(n!==-1){let c=`
399
+ const locale = (await props.params).locale as SupportedLocale;
400
+ setRequestLocale(locale);
401
+ `,p=o.indexOf("{",n);o=o.slice(0,p+1)+c+o.slice(p+1)}await u(s,o),await h(e)}};var Ce=async t=>{let r=N("Setting up Internationalization (next-intl)..."),e=Vr.join(t,".next-maker-temp-i18n");try{let{isSetup:i,reason:s}=await yt(t);if(i){r.fail(`i18n is already set up (${s}).`);return}await vt(t),await Ct(e,r),r.text="Copying i18n files...",await wt(t,e),r.text="Configuring project structure...",await Tt(t),await Et(t),await Rt(t),await It(t),r.text="Migrating to [locale] structure...",await Nt(t),r.text="Installing dependencies...",await F(t,"next-intl"),r.text="Formatting code...";let o=await Y(t);await k(t,o,"format"),r.succeed(Wr.green("Internationalization setup successfully!"))}catch(i){throw r.fail("Failed to setup Internationalization."),i}finally{await P(e)}};var{prompt:Kr}=Br,Ot=t=>{t.command("setup").description("Setup features in an existing Next.js project").option("--http-client <type>","Setup HTTP client (axios|fetch|both)").option("--dark-theme","Setup Dark Theme (Tailwind + next-themes)").option("--redux","Setup Redux Toolkit").option("--i18n","Setup next-intl for internationalization").action(async r=>{try{l(q.cyan(`
339
402
  \u{1F527} Setup Wizard
340
- `)),!e.httpClient&&!e.darkTheme&&!e.redux&&!e.i18n){let r=await hr([{type:"select",name:"feature",message:"What would you like to setup?",choices:["HTTP Client (Axios/Fetch)","Dark Theme","Redux Toolkit","Internationalization (next-intl)","Cancel"]}]);if(r.feature==="Dark Theme"){await me(process.cwd());return}if(r.feature==="Cancel"){p(j.yellow("Setup cancelled."));return}p(j.yellow(`
341
- \u26A0\uFE0F ${r.feature} setup is not implemented yet.`)),p(j.dim("This feature will be available in a future update."))}else e.httpClient&&(p(j.yellow(`
342
- \u26A0\uFE0F HTTP Client setup is not implemented yet.`)),p(j.dim("This feature will be available in a future update."))),e.darkTheme&&await me(process.cwd()),e.redux&&(p(j.yellow(`
343
- \u26A0\uFE0F Redux Toolkit setup is not implemented yet.`)),p(j.dim("This feature will be available in a future update."))),e.i18n&&(p(j.yellow(`
344
- \u26A0\uFE0F Internationalization setup is not implemented yet.`)),p(j.dim("This feature will be available in a future update.")))}catch(r){h.fail("Setup failed"),P(`${r}`),process.exit(1)}})};var ot=t=>{Re(t),it(t),ke(t),Me(t),Ye(t)};async function Sr(){ye({logger:e=>Q(e)});let t=new xr;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),ot(t),t.parse()}Sr().catch(t=>{let e=t&&typeof t=="object"&&"message"in t?t.message:String(t);Q(`Unexpected error: ${e}`)});
403
+ `));let e;if(!r.httpClient&&!r.darkTheme&&!r.redux&&!r.i18n){if(e=(await Kr([{type:"select",name:"feature",message:"What would you like to setup?",choices:["Dark Theme","Redux Toolkit","HTTP Client (Axios/Fetch)","Internationalization (next-intl)","Cancel"]}])).feature,e==="Cancel"){l(q.yellow("Setup cancelled."));return}e==="Dark Theme"?await Se(process.cwd()):e==="Redux Toolkit"?await ve(process.cwd()):e==="Internationalization (next-intl)"?await Ce(process.cwd()):(l(q.yellow(`
404
+ \u26A0\uFE0F ${e} setup is not implemented yet.`)),l(q.dim("This feature will be available in a future update.")))}else r.httpClient&&(l(q.yellow(`
405
+ \u26A0\uFE0F HTTP Client setup is not implemented yet.`)),l(q.dim("This feature will be available in a future update."))),r.darkTheme&&await Se(process.cwd()),r.redux&&await ve(process.cwd()),r.i18n&&await Ce(process.cwd())}catch(e){x.fail("Setup failed"),C(`${e}`),process.exit(1)}})};var $t=t=>{Fe(t),Ot(t),ze(t),Be(t),et(t)};async function Zr(){Ne({logger:r=>ne(r)});let t=new qr;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),$t(t),t.parse()}Zr().catch(t=>{let r=t&&typeof t=="object"&&"message"in t?t.message:String(t);ne(`Unexpected error: ${r}`)});
345
406
  //# sourceMappingURL=index.js.map