@teispace/next-maker 1.2.0 → 1.4.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 jr}from"commander";import de from"node:path";import L from"picocolors";import St from"ora";function b(t="",r){let e=St({text:t,...r});return e.start(),e}import Pt from"enquirer";var{prompt:vt}=Pt,Pe=async t=>{let r=await vt([{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 o=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!o.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 U from"node:fs/promises";import ve from"node:path";import{existsSync as pe}from"node:fs";var u=async t=>U.readFile(t,"utf-8"),f=async(t,r)=>{await U.mkdir(ve.dirname(t),{recursive:!0}),await U.writeFile(t,r,"utf-8")},te=async(t,r)=>{await U.mkdir(ve.dirname(r),{recursive:!0}),await U.copyFile(t,r)},x=async t=>{pe(t)&&await U.unlink(t)},S=async t=>{pe(t)&&await U.rm(t,{recursive:!0,force:!0})},W=async(t,r)=>{let e=await u(t),o=JSON.parse(e),s=r(o);await f(t,JSON.stringify(s,null,2))},d=t=>pe(t);import{exec as yt}from"node:child_process";import{promisify as Ct}from"node:util";var re=Ct(yt),ye=async(t,r)=>{try{await re("git init",{cwd:t}),await re("git add .",{cwd:t}),await re('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t}),r&&await re(`git remote add origin ${r}`,{cwd:t})}catch(e){console.warn("Failed to initialize git repository",e)}};import{exec as wt}from"node:child_process";import{promisify as Et}from"node:util";var me=Et(wt),Ce=async(t,r)=>{let e=`${r} install`;try{await me(e,{cwd:t})}catch(o){throw new Error(`Failed to install dependencies with ${r}: ${o}`)}},H=async(t,r,e)=>{let o=r==="npm"?`${r} run ${e}`:`${r} ${e}`;try{await me(o,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${e}': ${s}`)}},Tt=()=>{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"},K=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":Tt()},Rt=async(t,r,e)=>{if(e.length===0)return;let s=`${It(r)} ${e.join(" ")}`;try{await me(s,{cwd:t})}catch(i){throw new Error(`Failed to install packages with ${r}: ${i}`)}},It=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"}},X=async(t,r)=>{let e=await K(t);await Rt(t,e,[r])};import A from"picocolors";var Nt={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 z(t,r="reset"){let e=Nt[r]??(o=>o);console.log(e(t))}function ie(t){z(`\u2716 ${t}`,"red")}var v=ie;function p(t){z(t)}function we(){console.log(""),z("\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"),z("\u2551 \u2551","cyan"),z("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),z("\u2551 \u2551","cyan"),z("\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 Ee(t){let{logger:r=n=>console.error(n),exitOnCancel:e=process.env.NODE_ENV!=="test"}=t??{},o=()=>{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"){o();return}if(n instanceof Error){r(`Uncaught exception: ${n.message}`);return}r(`Uncaught exception: ${String(n)}`)},i=n=>{if(n instanceof Error){r(`Unhandled promise rejection: ${n.message}`);return}r(`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 $t=t=>t.charAt(0).toUpperCase()+t.slice(1),O=t=>t.replace(/-([a-z])/g,(r,e)=>e.toUpperCase()),F=t=>$t(O(t));import Ot from"ora";var h=Ot();import bt from"degit";var Te=async t=>{let r=b("Downloading template...");try{await bt("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 At 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 T={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 Re=async(t,r)=>{let e=b("Configuring package.json...");try{let o=r.gitRemote,s=r.gitHomepage,i=r.gitIssues;r.gitRemote&&(r.gitRemote.startsWith("git@github.com:")&&(o=r.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 W(At.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),i&&(n.bugs={url:i}),o&&(n.repository={type:"git",url:o})):(delete n.homepage,delete n.bugs,delete n.repository),r.redux||(delete n.dependencies[T.REDUX_TOOLKIT],delete n.dependencies[T.REACT_REDUX],delete n.dependencies[T.REDUX_PERSIST]),r.httpClient!=="none"||r.reactSecureStorage||delete n.dependencies[T.REACT_SECURE_STORAGE],r.i18n||delete n.dependencies[T.NEXT_INTL],r.darkMode||delete n.dependencies[T.NEXT_THEMES],r.httpClient==="none"?delete n.dependencies[T.AXIOS]:r.httpClient==="fetch"&&delete n.dependencies[T.AXIOS],n)),e.succeed("package.json configured.")}catch(o){throw e.fail("Failed to configure package.json."),o}};import l from"node:path";var Ie=async(t,r)=>{let e=b("Customizing features...");try{await jt(t,r),await _t(t,r),await kt(t,r),await Dt(t,r),await Ft(t,r),await Lt(t),await Gt(t),await Mt(t),e.succeed("Features customized.")}catch(o){throw e.fail("Failed to customize features."),o}},jt=async(t,r)=>{let e=l.join(t,a.HTTP_UTILS),o=r.httpClient!=="none"||r.reactSecureStorage;if(r.httpClient==="none"){if(await S(l.join(t,a.AXIOS_CLIENT)),await S(l.join(t,a.FETCH_CLIENT)),o)await f(l.join(e,"index.ts"),`export * from './token-store';
3
- `),await x(l.join(t,a.CLIENT_UTILS));else{await S(e);let i=l.join(t,a.UTILS_INDEX);if(d(i)){let c=await u(i);c=c.replace(/export \* from '\.\/http';\n/,""),await f(i,c)}await x(l.join(t,a.APP_APIS));let n=l.join(t,a.CONFIG_INDEX);if(d(n)){let c=await u(n);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await f(n,c)}}let s=l.join(t,a.CONSTANTS);if(d(s)){let i=await u(s);i=i.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),i=i.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await f(s,i)}if(await S(l.join(t,a.ERRORS_DIR)),!o){await S(l.join(t,a.COMMON_TYPES_DIR)),await S(l.join(t,a.UTILITY_TYPES_DIR));let i=l.join(t,a.TYPES_INDEX);if(d(i)){let n=await u(i);n=n.replace(/export \* from '\.\/utility';\n/,""),n=n.replace(/export \* from '\.\/common';\n/,""),await f(i,n)}}}else if(r.httpClient==="axios"){await S(l.join(t,a.FETCH_CLIENT));let s=await u(l.join(e,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await f(l.join(e,"index.ts"),s);let i=l.join(t,a.HTTP_TYPES);if(d(i)){let n=await u(i);n=n.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await f(i,n)}}else if(r.httpClient==="fetch"){await S(l.join(t,a.AXIOS_CLIENT));let s=await u(l.join(e,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await f(l.join(e,"index.ts"),s);let i=l.join(t,a.HTTP_TYPES);if(d(i)){let n=await u(i);n=n.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await f(i,n)}}},_t=async(t,r)=>{r.httpClient!=="none"||r.reactSecureStorage||await S(l.join(t,a.STORAGE_SERVICE))},kt=async(t,r)=>{if(!r.redux){await S(l.join(t,a.STORE)),await S(l.join(t,a.COUNTER_FEATURE)),await x(l.join(t,a.STORE_PROVIDER));let e=l.join(t,a.PROVIDERS_INDEX),o=await u(e);o=o.replace(/export \* from '\.\/StoreProvider';\n/,""),await f(e,o);let s=[l.join(t,a.ROOT_PAGE),l.join(t,a.LOCALE_PAGE)];for(let i of s)if(d(i)){let n=await u(i);n=n.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),n=n.replace(/<Counter\s*\/>\n?/g,""),await f(i,n)}}},Dt=async(t,r)=>{if(!r.darkMode){await x(l.join(t,a.THEME_PROVIDER));let e=l.join(t,a.PROVIDERS_INDEX),o=await u(e);o=o.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await f(e,o);let s=l.join(t,a.GLOBALS_CSS);if(d(s)){let i=await u(s);i=i.replace(/@custom-variant dark \(.*?\);\n\n/,""),i=i.replace(/@theme \{[\s\S]*?\}\n/,""),await f(s,i)}if(!r.i18n){let i=l.join(t,a.ROOT_LAYOUT);if(d(i)){let n=await u(i);n=n.replace(/bg-light dark:bg-dark /g,""),await f(i,n)}}}},Ft=async(t,r)=>{if(!r.i18n){await S(l.join(t,a.I18N_DIR)),await S(l.join(t,a.LOCALE_DIR)),await x(l.join(t,a.PROXY)),await x(l.join(t,a.MIDDLEWARE)),await x(l.join(t,a.I18N_TYPES)),await x(l.join(t,a.APP_LOCALES));let e=l.join(t,a.TYPES_INDEX);if(d(e)){let n=await u(e);n=n.replace(/export \* from '\.\/i18n';\n/,""),await f(e,n)}let o=l.join(t,a.CONFIG_INDEX);if(d(o)){let n=await u(o);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await f(o,n)}let s=l.join(t,a.NEXT_CONFIG);if(d(s)){let n=await u(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 f(s,n)}let i=l.join(t,a.COUNTER_COMPONENT);if(d(i)){let n=await u(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 f(i,n)}}},Lt=async t=>{await x(l.join(t,a.LICENSE))},Gt=async t=>{await x(l.join(t,a.CHANGELOG))},Mt=async t=>{await x(l.join(t,a.NVM_RC)),await x(l.join(t,a.NPM_RC))};import le from"node:path";var Ne=async(t,r)=>{let e=[],o=[];r.redux&&(e.push("import { StoreProvider } from '@/providers';"),o.push("StoreProvider")),r.darkMode&&(e.push("import { CustomThemeProvider } from '@/providers';"),o.push("CustomThemeProvider")),r.i18n&&(e.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),e.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
2
+ import{Command as xo}from"commander";import ye from"node:path";import Y from"picocolors";import Vt from"ora";function R(t="",i){let e=Vt({text:t,...i});return e.start(),e}import Wt from"enquirer";var{prompt:Bt}=Wt,Ne=async t=>{let i=await Bt([{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 r=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!r.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(i.company=i.author,i.gitRemote&&!i.gitHomepage){let e=i.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");i.gitHomepage=`${e}#readme`,i.gitIssues=`${e}/issues`}return i};import V from"node:fs/promises";import Oe from"node:path";import{existsSync as xe}from"node:fs";var m=async t=>V.readFile(t,"utf-8"),u=async(t,i)=>{await V.mkdir(Oe.dirname(t),{recursive:!0}),await V.writeFile(t,i,"utf-8")},_=async(t,i)=>{await V.mkdir(Oe.dirname(i),{recursive:!0}),await V.copyFile(t,i)},P=async t=>{xe(t)&&await V.unlink(t)},x=async t=>{xe(t)&&await V.rm(t,{recursive:!0,force:!0})},Z=async(t,i)=>{let e=await m(t),r=JSON.parse(e),s=i(r);await u(t,JSON.stringify(s,null,2))},l=t=>xe(t);import{exec as qt}from"node:child_process";import{promisify as Kt}from"node:util";var ae=Kt(qt),Ae=async(t,i)=>{try{await ae("git init",{cwd:t}),await ae("git add .",{cwd:t}),await ae('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t}),i&&await ae(`git remote add origin ${i}`,{cwd:t})}catch(e){console.warn("Failed to initialize git repository",e)}};import{exec as Zt}from"node:child_process";import{promisify as Qt}from"node:util";var he=Qt(Zt),$e=async(t,i)=>{let e=`${i} install`;try{await he(e,{cwd:t})}catch(r){throw new Error(`Failed to install dependencies with ${i}: ${r}`)}},j=async(t,i,e)=>{let r=i==="npm"?`${i} run ${e}`:`${i} ${e}`;try{await he(r,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${e}': ${s}`)}},ei=()=>{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"},M=async t=>{let{existsSync:i}=await import("node:fs"),e=await import("node:path");return i(e.join(t,"pnpm-lock.yaml"))?"pnpm":i(e.join(t,"yarn.lock"))?"yarn":i(e.join(t,"bun.lockb"))?"bun":i(e.join(t,"package-lock.json"))?"npm":ei()},ti=async(t,i,e)=>{if(e.length===0)return;let s=`${ii(i)} ${e.join(" ")}`;try{await he(s,{cwd:t})}catch(o){throw new Error(`Failed to install packages with ${i}: ${o}`)}},ii=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,i)=>{let e=await M(t);await ti(t,e,[i])};import k from"picocolors";var oi={reset:t=>t,red:k.red,green:k.green,yellow:k.yellow,blue:k.blue,cyan:k.cyan,magenta:k.magenta,white:k.white,gray:k.gray,bright:k.bold,dim:k.dim};function W(t,i="reset"){let e=oi[i]??(r=>r);console.log(e(t))}function ce(t){W(`\u2716 ${t}`,"red")}var w=ce;function p(t){W(t)}function be(){console.log(""),W("\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"),W("\u2551 \u2551","cyan"),W("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),W("\u2551 \u2551","cyan"),W("\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 _e(t){let{logger:i=n=>console.error(n),exitOnCancel:e=process.env.NODE_ENV!=="test"}=t??{},r=()=>{console.log(""),console.log(""),i("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"){r();return}if(n instanceof Error){i(`Uncaught exception: ${n.message}`);return}i(`Uncaught exception: ${String(n)}`)},o=n=>{if(n instanceof Error){i(`Unhandled promise rejection: ${n.message}`);return}i(`Unhandled promise rejection: ${String(n)}`)};return process.on("SIGINT",r),process.on("SIGTERM",r),process.on("uncaughtException",s),process.on("unhandledRejection",o),()=>{process.off("SIGINT",r),process.off("SIGTERM",r),process.off("uncaughtException",s),process.off("unhandledRejection",o)}}var ri=t=>t.charAt(0).toUpperCase()+t.slice(1),b=t=>t.replace(/-([a-z])/g,(i,e)=>e.toUpperCase()),X=t=>ri(b(t));import ni from"ora";var h=ni();import si from"degit";var je=async t=>{let i=R("Downloading template...");try{await si("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(t),i.succeed("Template downloaded successfully.")}catch(e){throw i.fail("Failed to download template."),e}};import ai 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 N={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 Fe=async(t,i)=>{let e=R("Configuring package.json...");try{let r=i.gitRemote,s=i.gitHomepage,o=i.gitIssues;i.gitRemote&&(i.gitRemote.startsWith("git@github.com:")&&(r=i.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"")),s||(s=`${r.replace(/\.git$/,"")}#readme`),o||(o=`${r.replace(/\.git$/,"")}/issues`),r.endsWith(".git")||(r=`${r}.git`)),await Z(ai.join(t,a.PACKAGE_JSON),n=>(n.name=i.projectName,n.version=i.version,n.description=i.description,n.author=i.author,delete n.packageManager,i.gitRemote?(s&&(n.homepage=s),o&&(n.bugs={url:o}),r&&(n.repository={type:"git",url:r})):(delete n.homepage,delete n.bugs,delete n.repository),i.redux||(delete n.dependencies[N.REDUX_TOOLKIT],delete n.dependencies[N.REACT_REDUX],delete n.dependencies[N.REDUX_PERSIST]),i.httpClient!=="none"||i.reactSecureStorage||delete n.dependencies[N.REACT_SECURE_STORAGE],i.i18n||delete n.dependencies[N.NEXT_INTL],i.darkMode||delete n.dependencies[N.NEXT_THEMES],i.httpClient==="none"?delete n.dependencies[N.AXIOS]:i.httpClient==="fetch"&&delete n.dependencies[N.AXIOS],n)),e.succeed("package.json configured.")}catch(r){throw e.fail("Failed to configure package.json."),r}};import f from"node:path";var ke=async(t,i)=>{let e=R("Customizing features...");try{await ci(t,i),await li(t,i),await pi(t,i),await mi(t,i),await di(t,i),await ui(t),await fi(t),await gi(t),e.succeed("Features customized.")}catch(r){throw e.fail("Failed to customize features."),r}},ci=async(t,i)=>{let e=f.join(t,a.HTTP_UTILS),r=i.httpClient!=="none"||i.reactSecureStorage;if(i.httpClient==="none"){if(await x(f.join(t,a.AXIOS_CLIENT)),await x(f.join(t,a.FETCH_CLIENT)),r)await u(f.join(e,"index.ts"),`export * from './token-store';
3
+ `),await P(f.join(t,a.CLIENT_UTILS));else{await x(e);let o=f.join(t,a.UTILS_INDEX);if(l(o)){let c=await m(o);c=c.replace(/export \* from '\.\/http';\n/,""),await u(o,c)}await P(f.join(t,a.APP_APIS));let n=f.join(t,a.CONFIG_INDEX);if(l(n)){let c=await m(n);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await u(n,c)}}let s=f.join(t,a.CONSTANTS);if(l(s)){let o=await m(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 x(f.join(t,a.ERRORS_DIR)),!r){await x(f.join(t,a.COMMON_TYPES_DIR)),await x(f.join(t,a.UTILITY_TYPES_DIR));let o=f.join(t,a.TYPES_INDEX);if(l(o)){let n=await m(o);n=n.replace(/export \* from '\.\/utility';\n/,""),n=n.replace(/export \* from '\.\/common';\n/,""),await u(o,n)}}}else if(i.httpClient==="axios"){await x(f.join(t,a.FETCH_CLIENT));let s=await m(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(l(o)){let n=await m(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(i.httpClient==="fetch"){await x(f.join(t,a.AXIOS_CLIENT));let s=await m(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(l(o)){let n=await m(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)}}},li=async(t,i)=>{i.httpClient!=="none"||i.reactSecureStorage||await x(f.join(t,a.STORAGE_SERVICE))},pi=async(t,i)=>{if(!i.redux){await x(f.join(t,a.STORE)),await x(f.join(t,a.COUNTER_FEATURE)),await P(f.join(t,a.STORE_PROVIDER));let e=f.join(t,a.PROVIDERS_INDEX),r=await m(e);r=r.replace(/export \* from '\.\/StoreProvider';\n/,""),await u(e,r);let s=[f.join(t,a.ROOT_PAGE),f.join(t,a.LOCALE_PAGE)];for(let o of s)if(l(o)){let n=await m(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)}}},mi=async(t,i)=>{if(!i.darkMode){await P(f.join(t,a.THEME_PROVIDER));let e=f.join(t,a.PROVIDERS_INDEX),r=await m(e);r=r.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await u(e,r);let s=f.join(t,a.GLOBALS_CSS);if(l(s)){let o=await m(s);o=o.replace(/@custom-variant dark \(.*?\);\n\n/,""),o=o.replace(/@theme \{[\s\S]*?\}\n/,""),await u(s,o)}if(!i.i18n){let o=f.join(t,a.ROOT_LAYOUT);if(l(o)){let n=await m(o);n=n.replace(/bg-light dark:bg-dark /g,""),await u(o,n)}}}},di=async(t,i)=>{if(!i.i18n){await x(f.join(t,a.I18N_DIR)),await x(f.join(t,a.LOCALE_DIR)),await P(f.join(t,a.PROXY)),await P(f.join(t,a.MIDDLEWARE)),await P(f.join(t,a.I18N_TYPES)),await P(f.join(t,a.APP_LOCALES));let e=f.join(t,a.TYPES_INDEX);if(l(e)){let n=await m(e);n=n.replace(/export \* from '\.\/i18n';\n/,""),await u(e,n)}let r=f.join(t,a.CONFIG_INDEX);if(l(r)){let n=await m(r);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await u(r,n)}let s=f.join(t,a.NEXT_CONFIG);if(l(s)){let n=await m(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(l(o)){let n=await m(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)}}},ui=async t=>{await P(f.join(t,a.LICENSE))},fi=async t=>{await P(f.join(t,a.CHANGELOG))},gi=async t=>{await P(f.join(t,a.NVM_RC)),await P(f.join(t,a.NPM_RC))};import Pe from"node:path";var De=async(t,i)=>{let e=[],r=[];i.redux&&(e.push("import { StoreProvider } from '@/providers';"),r.push("StoreProvider")),i.darkMode&&(e.push("import { CustomThemeProvider } from '@/providers';"),r.push("CustomThemeProvider")),i.i18n&&(e.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),e.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
4
4
  ${e.join(`
5
5
  `)}
6
6
 
7
7
  export const RootProvider = ({
8
8
  children,
9
- ${r.i18n?`locale,
9
+ ${i.i18n?`locale,
10
10
  messages,`:""}
11
11
  }: {
12
12
  children: React.ReactNode;
13
- ${r.i18n?`locale: SupportedLocale;
13
+ ${i.i18n?`locale: SupportedLocale;
14
14
  messages: AbstractIntlMessages;`:""}
15
15
  }) => {
16
16
  return (
17
- `,i="{children}";r.i18n&&(i=`<NextIntlClientProvider locale={locale} messages={messages}>
18
- ${i}
19
- </NextIntlClientProvider>`),r.darkMode&&(i=`<CustomThemeProvider>
20
- ${i}
21
- </CustomThemeProvider>`),r.redux&&(i=`<StoreProvider>
22
- ${i}
23
- </StoreProvider>`),i==="{children}"&&(i="<>{children}</>"),s+=` ${i}
17
+ `,o="{children}";i.i18n&&(o=`<NextIntlClientProvider locale={locale} messages={messages}>
18
+ ${o}
19
+ </NextIntlClientProvider>`),i.darkMode&&(o=`<CustomThemeProvider>
20
+ ${o}
21
+ </CustomThemeProvider>`),i.redux&&(o=`<StoreProvider>
22
+ ${o}
23
+ </StoreProvider>`),o==="{children}"&&(o="<>{children}</>"),s+=` ${o}
24
24
  );
25
25
  };
26
- `,await f(le.join(t,a.ROOT_PROVIDER),s)},$e=async(t,r)=>{if(!r.i18n){let e=`import type { Metadata } from 'next';
26
+ `,await u(Pe.join(t,a.ROOT_PROVIDER),s)},Le=async(t,i)=>{if(!i.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: '${r.projectName}',
40
- description: '${r.description}',
39
+ title: '${i.projectName}',
40
+ description: '${i.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={${r.darkMode?"true":"false"}}>
50
- <body className={\`\${livvic.variable} ${r.darkMode?"bg-light dark:bg-dark ":""}antialiased\`}>
49
+ <html lang="en" suppressHydrationWarning={${i.darkMode?"true":"false"}}>
50
+ <body className={\`\${livvic.variable} ${i.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 f(le.join(t,a.ROOT_LAYOUT),e);let o=r.redux?`import { Counter } from '@/features/counter';
58
+ `;await u(Pe.join(t,a.ROOT_LAYOUT),e);let r=i.redux?`import { Counter } from '@/features/counter';
59
59
 
60
- `:"",s=r.redux?`
61
- <Counter />`:"",i=`${o}export default function Home() {
60
+ `:"",s=i.redux?`
61
+ <Counter />`:"",o=`${r}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 ${r.projectName}</h1>
64
+ <h1 className="text-4xl font-bold">Welcome to ${i.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 f(le.join(t,a.ROOT_PAGE),i)}};import P from"node:path";import{readdir as Oe}from"node:fs/promises";var be=async(t,r)=>{await Ut(t,r),await Ht(t,r),await Xt(t,r),await zt(t,r),await Jt(t,r),await Yt(t,r),await Vt(t,r)},Ut=async(t,r)=>{r.preCommitHooks||(await S(P.join(t,a.HUSKY_DIR)),await x(P.join(t,a.COMMITLINT_CONFIG)),await x(P.join(t,a.LINTSTAGED_RC)),await W(P.join(t,a.PACKAGE_JSON),e=>(delete e.devDependencies[T.HUSKY],delete e.devDependencies[T.COMMITLINT_CLI],delete e.devDependencies[T.COMMITLINT_CONFIG],delete e.devDependencies[T.LINT_STAGED],delete e.scripts.prepare,delete e.scripts.postinstall,delete e.commitlint,delete e["lint-staged"],e)))},Ht=async(t,r)=>{r.commitizen||(await x(P.join(t,a.CZRC)),await W(P.join(t,a.PACKAGE_JSON),e=>(delete e.devDependencies[T.COMMITIZEN],delete e.devDependencies[T.CZ_CONVENTIONAL_CHANGELOG],delete e.config?.commitizen,e.config&&Object.keys(e.config).length===0&&delete e.config,delete e.scripts.commit,e)))},Xt=async(t,r)=>{r.ci||await S(P.join(t,a.GITHUB_WORKFLOWS))},zt=async(t,r)=>{let e=P.join(t,a.GITHUB_DIR);if(!r.keepTemplates)await S(P.join(e,a.GITHUB_ISSUE_TEMPLATE)),await x(P.join(e,a.GITHUB_PR_TEMPLATE));else{let o=P.join(e,a.GITHUB_ISSUE_TEMPLATE),s=P.join(e,a.GITHUB_PR_TEMPLATE),i=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(d(s)){let n=await u(s);n=i(n),await f(s,n)}try{if(d(o)){let n=await Oe(o);for(let c of n){let m=P.join(o,c),g=await u(m);g=i(g),await f(m,g)}}}catch{}}},Jt=async(t,r)=>{let e=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let o of e)r.communityFiles.includes(o)||await x(P.join(t,o))},Yt=async(t,r)=>{if(r.docker){let e=P.join(t,a.ENV_EXAMPLE);if(d(e)){let o=await u(e),s=(i,n)=>{let c=new RegExp(`${i}=.*`);c.test(o)?o=o.replace(c,`${i}=${n}`):o+=`${i}=${n}
70
- `};s("CONTAINER_NAME",r.containerName||"next-app"),s("IMAGE_NAME",r.imageName||"nextjs-starter"),s("IMAGE_TAG",r.imageTag||"latest"),await f(e,o)}}else{await x(P.join(t,a.DOCKERFILE)),await x(P.join(t,a.DOCKER_COMPOSE)),await x(P.join(t,a.DOCKERIGNORE));let e=P.join(t,a.ENV_EXAMPLE);if(d(e)){let o=await u(e);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 f(e,o)}}},Vt=async(t,r)=>{let e=async i=>{let n=await Oe(i,{withFileTypes:!0}),c=[];for(let m of n){let g=P.join(i,m.name);m.isDirectory()&&m.name!=="node_modules"&&m.name!==".git"?c.push(...await e(g)):m.isFile()&&m.name.toLowerCase()==="readme.md"&&c.push(g)}return c},o=await e(t),s=P.join(t,a.README);for(let i of o)i!==s&&await x(i);if(r.readme){let i=`# ${r.projectName}
69
+ `;await u(Pe.join(t,a.ROOT_PAGE),o)}};import S from"node:path";import{readdir as Me}from"node:fs/promises";var Ge=async(t,i)=>{await xi(t,i),await hi(t,i),await Pi(t,i),await yi(t,i),await Si(t,i),await vi(t,i),await Ci(t,i)},xi=async(t,i)=>{i.preCommitHooks||(await x(S.join(t,a.HUSKY_DIR)),await P(S.join(t,a.COMMITLINT_CONFIG)),await P(S.join(t,a.LINTSTAGED_RC)),await Z(S.join(t,a.PACKAGE_JSON),e=>(delete e.devDependencies[N.HUSKY],delete e.devDependencies[N.COMMITLINT_CLI],delete e.devDependencies[N.COMMITLINT_CONFIG],delete e.devDependencies[N.LINT_STAGED],delete e.scripts.prepare,delete e.scripts.postinstall,delete e.commitlint,delete e["lint-staged"],e)))},hi=async(t,i)=>{i.commitizen||(await P(S.join(t,a.CZRC)),await Z(S.join(t,a.PACKAGE_JSON),e=>(delete e.devDependencies[N.COMMITIZEN],delete e.devDependencies[N.CZ_CONVENTIONAL_CHANGELOG],delete e.config?.commitizen,e.config&&Object.keys(e.config).length===0&&delete e.config,delete e.scripts.commit,e)))},Pi=async(t,i)=>{i.ci||await x(S.join(t,a.GITHUB_WORKFLOWS))},yi=async(t,i)=>{let e=S.join(t,a.GITHUB_DIR);if(!i.keepTemplates)await x(S.join(e,a.GITHUB_ISSUE_TEMPLATE)),await P(S.join(e,a.GITHUB_PR_TEMPLATE));else{let r=S.join(e,a.GITHUB_ISSUE_TEMPLATE),s=S.join(e,a.GITHUB_PR_TEMPLATE),o=n=>n.replace(/Teispace/g,i.company).replace(/support@teispace\.com/g,i.email).replace(/Next\.js Starter/g,i.projectName).replace(/\[AUTHOR\]/g,i.author).replace(/\[COMPANY\]/g,i.company).replace(/\[EMAIL\]/g,i.email);if(l(s)){let n=await m(s);n=o(n),await u(s,n)}try{if(l(r)){let n=await Me(r);for(let c of n){let d=S.join(r,c),g=await m(d);g=o(g),await u(d,g)}}}catch{}}},Si=async(t,i)=>{let e=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let r of e)i.communityFiles.includes(r)||await P(S.join(t,r))},vi=async(t,i)=>{if(i.docker){let e=S.join(t,a.ENV_EXAMPLE);if(l(e)){let r=await m(e),s=(o,n)=>{let c=new RegExp(`${o}=.*`);c.test(r)?r=r.replace(c,`${o}=${n}`):r+=`${o}=${n}
70
+ `};s("CONTAINER_NAME",i.containerName||"next-app"),s("IMAGE_NAME",i.imageName||"nextjs-starter"),s("IMAGE_TAG",i.imageTag||"latest"),await u(e,r)}}else{await P(S.join(t,a.DOCKERFILE)),await P(S.join(t,a.DOCKER_COMPOSE)),await P(S.join(t,a.DOCKERIGNORE));let e=S.join(t,a.ENV_EXAMPLE);if(l(e)){let r=await m(e);r=r.replace(/# Docker Compose Configuration\n/,""),r=r.replace(/CONTAINER_NAME=.*\n/,""),r=r.replace(/IMAGE_NAME=.*\n/,""),r=r.replace(/IMAGE_TAG=.*\n/,""),await u(e,r)}}},Ci=async(t,i)=>{let e=async o=>{let n=await Me(o,{withFileTypes:!0}),c=[];for(let d of n){let g=S.join(o,d.name);d.isDirectory()&&d.name!=="node_modules"&&d.name!==".git"?c.push(...await e(g)):d.isFile()&&d.name.toLowerCase()==="readme.md"&&c.push(g)}return c},r=await e(t),s=S.join(t,a.README);for(let o of r)o!==s&&await P(o);if(i.readme){let o=`# ${i.projectName}
71
71
 
72
- ${r.description}
72
+ ${i.description}
73
73
 
74
74
  ## Getting Started
75
75
 
76
76
  First, run the development server:
77
77
 
78
78
  \`\`\`bash
79
- ${r.packageManager==="npm"?"npm run dev":r.packageManager+" dev"}
79
+ ${i.packageManager==="npm"?"npm run dev":i.packageManager+" dev"}
80
80
  \`\`\`
81
81
 
82
82
  Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
83
- `;await f(s,i)}else await x(s)};var Ae=t=>{t.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async r=>{await Wt(r)})},Wt=async t=>{we(),p("Welcome to the Teispace Next.js App Creator!"),p("");let r=await Pe(t),e=de.resolve(process.cwd(),r.projectName);d(e)&&(console.error(L.red(`Error: Directory ${r.projectName} already exists.`)),process.exit(1));let o=b("Initializing project..."),s=async()=>{if(d(e)){o.stop(),console.log(L.yellow(`
84
- Cleaning up: Deleting directory ${r.projectName}...`));try{await S(e),console.log(L.green("Cleanup successful."))}catch(n){console.error(L.red(`Failed to clean up directory ${r.projectName}:`),n)}}},i=async()=>{console.log(L.red(`
85
- Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",i),process.on("SIGTERM",i);try{if(await Te(e),await Re(e,r),await Ie(e,r),o.text="Generating code...",await Ne(e,r),await $e(e,r),o.text="Setting up developer tools...",await be(e,r),o.text="Initializing Git...",await ye(e,r.gitRemote),o.text="Installing dependencies...",await Ce(e,r.packageManager),o.text="Formatting and Linting...",await H(e,r.packageManager,"format"),await H(e,r.packageManager,"lint:fix"),r.copyEnv){o.text="Creating .env file...";let n=de.join(e,".env.example"),c=de.join(e,".env");d(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",i),process.off("SIGTERM",i),o.succeed(L.green(`Project ${r.projectName} created successfully!`)),p(""),p("To get started:"),p(L.cyan(` cd ${r.projectName}`)),p(L.cyan(` ${r.packageManager==="npm"?"npm run dev":r.packageManager+" dev"}`)),p("")}catch(n){o.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import w from"picocolors";import ge from"node:path";import Kt from"enquirer";var{prompt:Bt}=Kt,je=async(t,r,e,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."}),r&&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}})),e&&e!=="none"&&i===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 m=c.length>0?await Bt(c):{};return{featureName:t||m.featureName,hasRedux:r||!1,createStore:o===!0?!1:s!==void 0?!0:m.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:m.persistStore||!1,httpClient:e||"none",createService:i===!0?!1:n!==void 0?!0:m.createService||!1,selectedHttpClient:n||m.selectedHttpClient||(e==="both"?"fetch":e!=="none"?e:void 0)}};import{readFile as qt,access as ue}from"node:fs/promises";import B from"node:path";var V=async t=>{let r=!1,e=!1,o=!1,s=!1;try{let i=B.join(t,"package.json"),n=await qt(i,"utf-8"),c=JSON.parse(n),m={...c.dependencies,...c.devDependencies};r=!!(m["@reduxjs/toolkit"]&&m["react-redux"]),e=!!m.axios,s=!!m["next-intl"];let g=B.join(t,"src","lib","utils","http","axios-client");try{await ue(g),e=e&&!0}catch{e=!1}let I=B.join(t,"src","lib","utils","http","fetch-client");try{await ue(I),o=!0}catch{o=!1}let y;return e&&o?y="both":e?y="axios":o?y="fetch":y="none",{hasRedux:r,httpClient:y,hasI18n:s}}catch(i){throw new Error(`Failed to detect project setup: ${i}`)}},_e=async(t,r,e=B.join("src","features"))=>{let o=B.join(t,e,r);try{return await ue(o),!0}catch{return!1}};import{writeFile as k,mkdir as q}from"node:fs/promises";import N from"node:path";var ke=async t=>{let{featurePath:r}=t;await q(N.join(r,"components"),{recursive:!0}),await q(N.join(r,"hooks"),{recursive:!0}),await q(N.join(r,"types"),{recursive:!0}),t.createStore&&await q(N.join(r,"store"),{recursive:!0}),t.createService&&await q(N.join(r,"services"),{recursive:!0}),await Zt(t),await Qt(t),await er(t),await ir(t),t.createStore&&await tr(t),t.createService&&t.httpClient&&await rr(t)};var Zt=async t=>{let{featureName:r,featurePath:e}=t,o=F(r),s=`use${o}`,i=`'use client';
83
+ `;await u(s,o)}else await P(s)};var He=t=>{t.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async i=>{await wi(i)})},wi=async t=>{be(),p("Welcome to the Teispace Next.js App Creator!"),p("");let i=await Ne(t),e=ye.resolve(process.cwd(),i.projectName);l(e)&&(console.error(Y.red(`Error: Directory ${i.projectName} already exists.`)),process.exit(1));let r=R("Initializing project..."),s=async()=>{if(l(e)){r.stop(),console.log(Y.yellow(`
84
+ Cleaning up: Deleting directory ${i.projectName}...`));try{await x(e),console.log(Y.green("Cleanup successful."))}catch(n){console.error(Y.red(`Failed to clean up directory ${i.projectName}:`),n)}}},o=async()=>{console.log(Y.red(`
85
+ Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await je(e),await Fe(e,i),await ke(e,i),r.text="Generating code...",await De(e,i),await Le(e,i),r.text="Setting up developer tools...",await Ge(e,i),r.text="Initializing Git...",await Ae(e,i.gitRemote),r.text="Installing dependencies...",await $e(e,i.packageManager),r.text="Formatting and Linting...",await j(e,i.packageManager,"format"),await j(e,i.packageManager,"lint:fix"),i.copyEnv){r.text="Creating .env file...";let n=ye.join(e,".env.example"),c=ye.join(e,".env");l(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",o),process.off("SIGTERM",o),r.succeed(Y.green(`Project ${i.projectName} created successfully!`)),p(""),p("To get started:"),p(Y.cyan(` cd ${i.projectName}`)),p(Y.cyan(` ${i.packageManager==="npm"?"npm run dev":i.packageManager+" dev"}`)),p("")}catch(n){r.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import I from"picocolors";import Ce from"node:path";import Ti from"enquirer";var{prompt:Ei}=Ti,Ue=async(t,i,e,r,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."}),i&&r===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 d=c.length>0?await Ei(c):{};return{featureName:t||d.featureName,hasRedux:i||!1,createStore:r===!0?!1:s!==void 0?!0:d.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:d.persistStore||!1,httpClient:e||"none",createService:o===!0?!1:n!==void 0?!0:d.createService||!1,selectedHttpClient:n||d.selectedHttpClient||(e==="both"?"fetch":e!=="none"?e:void 0)}};import{readFile as Ii,access as Se}from"node:fs/promises";import Q from"node:path";var K=async t=>{let i=!1,e=!1,r=!1,s=!1;try{let o=Q.join(t,"package.json"),n=await Ii(o,"utf-8"),c=JSON.parse(n),d={...c.dependencies,...c.devDependencies};i=!!(d["@reduxjs/toolkit"]&&d["react-redux"]),e=!!d.axios,s=!!d["next-intl"];let g=Q.join(t,"src","lib","utils","http","axios-client");try{await Se(g),e=e&&!0}catch{e=!1}let C=Q.join(t,"src","lib","utils","http","fetch-client");try{await Se(C),r=!0}catch{r=!1}let y;return e&&r?y="both":e?y="axios":r?y="fetch":y="none",{hasRedux:i,httpClient:y,hasI18n:s}}catch(o){throw new Error(`Failed to detect project setup: ${o}`)}},Xe=async(t,i,e=Q.join("src","features"))=>{let r=Q.join(t,e,i);try{return await Se(r),!0}catch{return!1}};import{writeFile as G,mkdir as ee}from"node:fs/promises";import A from"node:path";var Ye=async t=>{let{featurePath:i}=t;await ee(A.join(i,"components"),{recursive:!0}),await ee(A.join(i,"hooks"),{recursive:!0}),await ee(A.join(i,"types"),{recursive:!0}),t.createStore&&await ee(A.join(i,"store"),{recursive:!0}),t.createService&&await ee(A.join(i,"services"),{recursive:!0}),await Ri(t),await Ni(t),await Oi(t),await bi(t),t.createStore&&await Ai(t),t.createService&&t.httpClient&&await $i(t)};var Ri=async t=>{let{featureName:i,featurePath:e}=t,r=X(i),s=`use${r}`,o=`'use client';
86
86
  import { ${s} } from '../hooks/${s}';
87
87
 
88
- export function ${o}() {
88
+ export function ${r}() {
89
89
  const {} = ${s}();
90
90
 
91
91
  return (
92
92
  <div>
93
- <h2>${o} Component</h2>
93
+ <h2>${r} Component</h2>
94
94
  {/* Add your component UI here */}
95
95
  </div>
96
96
  );
97
97
  }
98
98
 
99
- export default ${o};
100
- `;await k(N.join(e,"components",`${o}.tsx`),i)},Qt=async t=>{let{featureName:r,featurePath:e,createStore:o}=t,s=F(r),i=`use${s}`,n;o?n=`'use client';
99
+ export default ${r};
100
+ `;await G(A.join(e,"components",`${r}.tsx`),o)},Ni=async t=>{let{featureName:i,featurePath:e,createStore:r}=t,s=X(i),o=`use${s}`,n;r?n=`'use client';
101
101
  import { useAppDispatch, useAppSelector } from '@/store/hooks';
102
- import { select${s}State, setLoading, setError } from '../store/${r}.selectors';
102
+ import { select${s}State, setLoading, setError } from '../store/${i}.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 k(N.join(e,"hooks",`${i}.ts`),n)},er=async t=>{let{featureName:r,featurePath:e,createStore:o}=t,n=`export interface ${`${F(r)}State`} {
136
+ `,await G(A.join(e,"hooks",`${o}.ts`),n)},Oi=async t=>{let{featureName:i,featurePath:e,createStore:r}=t,n=`export interface ${`${X(i)}State`} {
137
137
  // Add your state properties here
138
- ${o?`loading: boolean;
138
+ ${r?`loading: boolean;
139
139
  error: string | null;`:"// example: value: string;"}
140
140
  }
141
- `;await k(N.join(e,"types",`${r}.types.ts`),n)},tr=async t=>{let{featureName:r,featurePath:e,persistStore:o}=t,s=F(r),i=O(r),n=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
142
- import { ${s}State } from '../types/${r}.types';
141
+ `;await G(A.join(e,"types",`${i}.types.ts`),n)},Ai=async t=>{let{featureName:i,featurePath:e,persistStore:r}=t,s=X(i),o=b(i),n=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
142
+ import { ${s}State } from '../types/${i}.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 k(N.join(e,"store",`${r}.slice.ts`),n);let c=`import { RootState } from '@/store/rootReducer';
169
+ export const ${o}Reducer = ${o}Slice.reducer;
170
+ `;await G(A.join(e,"store",`${i}.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 './${r}.slice';
174
- `;if(await k(N.join(e,"store",`${r}.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 './${i}.slice';
174
+ `;if(await G(A.join(e,"store",`${i}.selectors.ts`),c),r){let g=`import { PersistConfig } from 'redux-persist';
175
175
  import storage from 'redux-persist/lib/storage';
176
- import { ${s}State } from '../types/${r}.types';
176
+ import { ${s}State } from '../types/${i}.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 k(N.join(e,"store","persist.ts"),g)}let m=`export * from './${r}.slice';
184
- export * from './${r}.selectors';${o?`
183
+ `;await G(A.join(e,"store","persist.ts"),g)}let d=`export * from './${i}.slice';
184
+ export * from './${i}.selectors';${r?`
185
185
  export * from './persist';`:""}
186
- `;await k(N.join(e,"store","index.ts"),m)},rr=async t=>{let{featureName:r,featurePath:e,httpClient:o}=t,s=O(r),i;o==="axios"?i=`import { AppApis } from '@/lib/config';
186
+ `;await G(A.join(e,"store","index.ts"),d)},$i=async t=>{let{featureName:i,featurePath:e,httpClient:r}=t,s=b(i),o;r==="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,40 +201,40 @@ export const ${s}Service = {
201
201
  return fetchClient.get<string>(AppApis.${s}.getAll);
202
202
  },
203
203
  };
204
- `,await k(N.join(e,"services",`${r}.service.ts`),i)},ir=async t=>{let{featureName:r,featurePath:e,createStore:o,createService:s}=t,i=F(r),n=`export { default as ${i} } from './components/${i}';
205
- export { use${i} } from './hooks/use${i}';
206
- export * from './types/${r}.types';${o?`
204
+ `,await G(A.join(e,"services",`${i}.service.ts`),o)},bi=async t=>{let{featureName:i,featurePath:e,createStore:r,createService:s}=t,o=X(i),n=`export { default as ${o} } from './components/${o}';
205
+ export { use${o} } from './hooks/use${o}';
206
+ export * from './types/${i}.types';${r?`
207
207
  export * from './store';`:""}${s?`
208
- export * from './services/${r}.service';`:""}
209
- `;await k(N.join(e,"index.ts"),n)};import{readFile as De,writeFile as Fe}from"node:fs/promises";import fe from"node:path";var Le=async(t,r,e,o=fe.join("src","features"))=>{let s=fe.join(t,"src","store","rootReducer.ts");try{let i=await De(s,"utf-8"),n=O(r),c=`${n}Reducer`,m=e?`${n}PersistConfig`:"",g=o.replace(/^src\//,"@/"),I=e?`import { ${c}, ${m} } from '${g}/${r}/store';`:`import { ${c} } from '${g}/${r}/store';`,y=/import\s+.*\s+from\s+['"].*['"];?\n/g,E=i.match(y);if(E&&E.length>0){let R=E[E.length-1],_=i.lastIndexOf(R);i=i.slice(0,_+R.length)+I+`
210
- `+i.slice(_+R.length)}else i=I+`
211
- `+i;let C=/combineReducers\(\{([^}]*)\}\)/s,j=i.match(C);if(j){let R=j[1],_=e?`
212
- ${n}: persistReducer(${m}, ${c}),`:`
213
- ${n}: ${c},`,ce=R.trimEnd()+_;i=i.replace(C,`combineReducers({${ce}
214
- })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await Fe(s,i)}catch(i){throw new Error(`Failed to register feature in rootReducer: ${i}`)}},Ge=async(t,r,e,o)=>{let s=fe.join(t,"src","store","rootReducer.ts");try{let i=await De(s,"utf-8"),n=O(r),c=`${n}Reducer`,m=e?`${n}PersistConfig`:"",g=o.replace(/^src\//,"@/"),I=e?`import { ${c}, ${m} } from '${g}/${r}';`:`import { ${c} } from '${g}/${r}';`,y=/import\s+.*\s+from\s+['"].*['"];?\n/g,E=i.match(y);if(E&&E.length>0){let R=E[E.length-1],_=i.lastIndexOf(R);i=i.slice(0,_+R.length)+I+`
215
- `+i.slice(_+R.length)}else i=I+`
216
- `+i;let C=/combineReducers\(\{([^}]*)\}\)/s,j=i.match(C);if(j){let R=j[1],_=e?`
217
- ${n}: persistReducer(${m}, ${c}),`:`
218
- ${n}: ${c},`,ce=R.trimEnd()+_;i=i.replace(C,`combineReducers({${ce}
219
- })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await Fe(s,i)}catch(i){throw new Error(`Failed to register slice in rootReducer: ${i}`)}};import{readFile as or,writeFile as nr}from"node:fs/promises";import sr from"node:path";var oe=async t=>{let{serviceName:r,projectPath:e}=t,o=O(r),s=sr.join(e,"src","lib","config","app-apis.ts");try{let i=await or(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}/${r}\`,
221
- getAll: \`\${API_PREFIX}/${r}\`,
222
- },`,m=/(\s*)\} as const;/;if(!i.match(m))throw new Error("Could not find closing brace of AppApis object");let I=i.lastIndexOf("} as const;"),y=i.substring(0,I),E=i.substring(I),C=y.trim().endsWith(","),j=y.match(/:\s*\{[^}]*\},\s*$/),R;j||C?R=`${y}
208
+ export * from './services/${i}.service';`:""}
209
+ `;await G(A.join(e,"index.ts"),n)};import{readFile as Je,writeFile as ze}from"node:fs/promises";import ve from"node:path";var Ve=async(t,i,e,r=ve.join("src","features"))=>{let s=ve.join(t,"src","store","rootReducer.ts");try{let o=await Je(s,"utf-8"),n=b(i),c=`${n}Reducer`,d=e?`${n}PersistConfig`:"",g=r.replace(/^src\//,"@/"),C=e?`import { ${c}, ${d} } from '${g}/${i}/store';`:`import { ${c} } from '${g}/${i}/store';`,y=/import\s+.*\s+from\s+['"].*['"];?\n/g,T=o.match(y);if(T&&T.length>0){let O=T[T.length-1],L=o.lastIndexOf(O);o=o.slice(0,L+O.length)+C+`
210
+ `+o.slice(L+O.length)}else o=C+`
211
+ `+o;let E=/combineReducers\(\{([^}]*)\}\)/s,D=o.match(E);if(D){let O=D[1],L=e?`
212
+ ${n}: persistReducer(${d}, ${c}),`:`
213
+ ${n}: ${c},`,ge=O.trimEnd()+L;o=o.replace(E,`combineReducers({${ge}
214
+ })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await ze(s,o)}catch(o){throw new Error(`Failed to register feature in rootReducer: ${o}`)}},We=async(t,i,e,r)=>{let s=ve.join(t,"src","store","rootReducer.ts");try{let o=await Je(s,"utf-8"),n=b(i),c=`${n}Reducer`,d=e?`${n}PersistConfig`:"",g=r.replace(/^src\//,"@/"),C=e?`import { ${c}, ${d} } from '${g}/${i}';`:`import { ${c} } from '${g}/${i}';`,y=/import\s+.*\s+from\s+['"].*['"];?\n/g,T=o.match(y);if(T&&T.length>0){let O=T[T.length-1],L=o.lastIndexOf(O);o=o.slice(0,L+O.length)+C+`
215
+ `+o.slice(L+O.length)}else o=C+`
216
+ `+o;let E=/combineReducers\(\{([^}]*)\}\)/s,D=o.match(E);if(D){let O=D[1],L=e?`
217
+ ${n}: persistReducer(${d}, ${c}),`:`
218
+ ${n}: ${c},`,ge=O.trimEnd()+L;o=o.replace(E,`combineReducers({${ge}
219
+ })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await ze(s,o)}catch(o){throw new Error(`Failed to register slice in rootReducer: ${o}`)}};import{readFile as _i,writeFile as ji}from"node:fs/promises";import Fi from"node:path";var le=async t=>{let{serviceName:i,projectPath:e}=t,r=b(i),s=Fi.join(e,"src","lib","config","app-apis.ts");try{let o=await _i(s,"utf-8");if(o.includes(`${r}:`))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=` ${r}: {
220
+ base: \`\${API_PREFIX}/${i}\`,
221
+ getAll: \`\${API_PREFIX}/${i}\`,
222
+ },`,d=/(\s*)\} as const;/;if(!o.match(d))throw new Error("Could not find closing brace of AppApis object");let C=o.lastIndexOf("} as const;"),y=o.substring(0,C),T=o.substring(C),E=y.trim().endsWith(","),D=y.match(/:\s*\{[^}]*\},\s*$/),O;D||E?O=`${y}
223
223
  ${c}
224
- ${E}`:R=y.trimEnd()+`
224
+ ${T}`:O=y.trimEnd()+`
225
225
  `+c+`
226
- `+E,await nr(s,R)}catch(i){throw new Error(`Failed to register API endpoints: ${i}`)}};var Me=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 o=process.cwd();e.store&&!["persist","no-persist"].includes(e.store)&&(v("Invalid --store option. Use: persist or no-persist"),process.exit(1)),e.service&&!["axios","fetch"].includes(e.service)&&(v("Invalid --service option. Use: axios or fetch"),process.exit(1)),e.skipStore&&e.store&&(v("Cannot use --skip-store and --store together"),process.exit(1)),e.skipService&&e.service&&(v("Cannot use --skip-service and --service together"),process.exit(1)),p(w.cyan(`
226
+ `+T,await ji(s,O)}catch(o){throw new Error(`Failed to register API endpoints: ${o}`)}};var Be=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(i,e)=>{try{let r=process.cwd();e.store&&!["persist","no-persist"].includes(e.store)&&(w("Invalid --store option. Use: persist or no-persist"),process.exit(1)),e.service&&!["axios","fetch"].includes(e.service)&&(w("Invalid --service option. Use: axios or fetch"),process.exit(1)),e.skipStore&&e.store&&(w("Cannot use --skip-store and --store together"),process.exit(1)),e.skipService&&e.service&&(w("Cannot use --skip-service and --service together"),process.exit(1)),p(I.cyan(`
227
227
  \u{1F3AF} Feature Generator
228
- `)),h.start("Detecting project setup...");let s=await V(o);h.succeed("Project setup detected"),p(w.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),p(w.dim(` HTTP Client: ${s.httpClient}`)),p(w.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
229
- `));let i=await je(r,s.hasRedux,s.httpClient,e.skipStore,e.store,e.skipService,e.service),n=e.path||ge.join("src","features"),c=ge.join(o,n,i.featureName);await _e(o,i.featureName,n)&&(v(`Feature '${i.featureName}' already exists at ${n}!`),process.exit(1)),h.start("Generating feature files..."),await ke({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 oe({serviceName:i.featureName,projectPath:o}),h.succeed("API endpoints registered")),i.createStore&&s.hasRedux&&(h.start("Registering feature in rootReducer..."),await Le(o,i.featureName,i.persistStore,n),h.succeed("Feature registered in rootReducer"));let g=ge.join(n,i.featureName);p(w.green(`
230
- \u2728 Feature '${i.featureName}' created successfully!
231
- `)),p(w.dim("Generated files:")),p(w.dim(` \u{1F4C2} ${g}/`)),p(w.dim(" \u251C\u2500\u2500 components/")),p(w.dim(" \u251C\u2500\u2500 hooks/")),p(w.dim(" \u251C\u2500\u2500 types/")),i.createStore&&p(w.dim(" \u251C\u2500\u2500 store/")),i.createService&&p(w.dim(" \u251C\u2500\u2500 services/")),p(w.dim(` \u2514\u2500\u2500 index.ts
232
- `)),p(w.cyan("Next steps:"));let I=n.replace(/^src\//,"@/");p(w.dim(` 1. Import and use the feature: import { ${i.featureName} } from '${I}/${i.featureName}'`)),i.createStore&&p(w.dim(` 2. Customize your Redux slice in: ${g}/store/`)),i.createService&&p(w.dim(` 3. Add API methods in: ${g}/services/${i.featureName}.service.ts`)),p("")}catch(o){h.fail("Feature generation failed"),v(`${o}`),process.exit(1)}})};import $ from"picocolors";import G from"node:path";import{existsSync as hr}from"node:fs";import{mkdir as xr}from"node:fs/promises";import ar from"enquirer";var{prompt:cr}=ar,Ue=async(t,r,e)=>{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."}),r===void 0&&e===void 0&&o.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=o.length>0?await cr(o):{};return{sliceName:t||s.sliceName,persistSlice:r===!0?!0:e===!1?!1:s.persistSlice||!1}};import{writeFile as Z,mkdir as pr}from"node:fs/promises";import Q from"node:path";var He=async t=>{let{sliceName:r,slicePath:e,persistSlice:o}=t;await pr(e,{recursive:!0});let s=F(r),i=O(r);await mr(r,e,s),await lr(r,e,s,i),await dr(r,e,s,i),o&&await ur(r,e,s,i),await fr(r,e,o)},mr=async(t,r,e)=>{let o=`export interface ${e}State {
228
+ `)),h.start("Detecting project setup...");let s=await K(r);h.succeed("Project setup detected"),p(I.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),p(I.dim(` HTTP Client: ${s.httpClient}`)),p(I.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
229
+ `));let o=await Ue(i,s.hasRedux,s.httpClient,e.skipStore,e.store,e.skipService,e.service),n=e.path||Ce.join("src","features"),c=Ce.join(r,n,o.featureName);await Xe(r,o.featureName,n)&&(w(`Feature '${o.featureName}' already exists at ${n}!`),process.exit(1)),h.start("Generating feature files..."),await Ye({featureName:o.featureName,featurePath:c,createStore:o.createStore,persistStore:o.persistStore,createService:o.createService,httpClient:o.selectedHttpClient}),h.succeed("Feature files generated"),o.createService&&(h.start("Registering API endpoints..."),await le({serviceName:o.featureName,projectPath:r}),h.succeed("API endpoints registered")),o.createStore&&s.hasRedux&&(h.start("Registering feature in rootReducer..."),await Ve(r,o.featureName,o.persistStore,n),h.succeed("Feature registered in rootReducer"));let g=Ce.join(n,o.featureName);p(I.green(`
230
+ \u2728 Feature '${o.featureName}' created successfully!
231
+ `)),p(I.dim("Generated files:")),p(I.dim(` \u{1F4C2} ${g}/`)),p(I.dim(" \u251C\u2500\u2500 components/")),p(I.dim(" \u251C\u2500\u2500 hooks/")),p(I.dim(" \u251C\u2500\u2500 types/")),o.createStore&&p(I.dim(" \u251C\u2500\u2500 store/")),o.createService&&p(I.dim(" \u251C\u2500\u2500 services/")),p(I.dim(` \u2514\u2500\u2500 index.ts
232
+ `)),p(I.cyan("Next steps:"));let C=n.replace(/^src\//,"@/");p(I.dim(` 1. Import and use the feature: import { ${o.featureName} } from '${C}/${o.featureName}'`)),o.createStore&&p(I.dim(` 2. Customize your Redux slice in: ${g}/store/`)),o.createService&&p(I.dim(` 3. Add API methods in: ${g}/services/${o.featureName}.service.ts`)),p("")}catch(r){h.fail("Feature generation failed"),w(`${r}`),process.exit(1)}})};import $ from"picocolors";import J from"node:path";import{existsSync as Ji}from"node:fs";import{mkdir as zi}from"node:fs/promises";import ki from"enquirer";var{prompt:Di}=ki,qe=async(t,i,e)=>{let r=[];t||r.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."}),i===void 0&&e===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=r.length>0?await Di(r):{};return{sliceName:t||s.sliceName,persistSlice:i===!0?!0:e===!1?!1:s.persistSlice||!1}};import{writeFile as te,mkdir as Li}from"node:fs/promises";import ie from"node:path";var Ke=async t=>{let{sliceName:i,slicePath:e,persistSlice:r}=t;await Li(e,{recursive:!0});let s=X(i),o=b(i);await Mi(i,e,s),await Gi(i,e,s,o),await Hi(i,e,s,o),r&&await Ui(i,e,s,o),await Xi(i,e,r)},Mi=async(t,i,e)=>{let r=`export interface ${e}State {
233
233
  loading: boolean;
234
234
  error: string | null;
235
235
  // Add your state properties here
236
236
  }
237
- `;await Z(Q.join(r,`${t}.types.ts`),o)},lr=async(t,r,e,o)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
237
+ `;await te(ie.join(i,`${t}.types.ts`),r)},Gi=async(t,i,e,r)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
238
238
  import { ${e}State } from './${t}.types';
239
239
 
240
240
  const initialState: ${e}State = {
@@ -243,8 +243,8 @@ const initialState: ${e}State = {
243
243
  // Add your initial state here
244
244
  };
245
245
 
246
- export const ${o}Slice = createSlice({
247
- name: '${o}',
246
+ export const ${r}Slice = createSlice({
247
+ name: '${r}',
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 } = ${r}Slice.actions;
264
264
 
265
- export const ${o}Reducer = ${o}Slice.reducer;
266
- `;await Z(Q.join(r,`${t}.slice.ts`),s)},dr=async(t,r,e,o)=>{let s=`import { RootState } from '@/store/rootReducer';
265
+ export const ${r}Reducer = ${r}Slice.reducer;
266
+ `;await te(ie.join(i,`${t}.slice.ts`),s)},Hi=async(t,i,e,r)=>{let s=`import { RootState } from '@/store/rootReducer';
267
267
 
268
- export const select${e}State = (state: RootState) => state.${o};
268
+ export const select${e}State = (state: RootState) => state.${r};
269
269
  export { setLoading, setError, resetState } from './${t}.slice';
270
- `;await Z(Q.join(r,`${t}.selectors.ts`),s)},ur=async(t,r,e,o)=>{let s=`import { PersistConfig } from 'redux-persist';
270
+ `;await te(ie.join(i,`${t}.selectors.ts`),s)},Ui=async(t,i,e,r)=>{let s=`import { PersistConfig } from 'redux-persist';
271
271
  import storage from 'redux-persist/lib/storage';
272
272
  import { ${e}State } from './${t}.types';
273
273
 
274
- export const ${o}PersistConfig: PersistConfig<${e}State> = {
275
- key: '${o}',
274
+ export const ${r}PersistConfig: PersistConfig<${e}State> = {
275
+ key: '${r}',
276
276
  storage,
277
277
  // whitelist: ['someField'], // Specify which fields to persist
278
278
  };
279
- `;await Z(Q.join(r,"persist.ts"),s)},fr=async(t,r,e)=>{let o=`export * from './${t}.slice';
279
+ `;await te(ie.join(i,"persist.ts"),s)},Xi=async(t,i,e)=>{let r=`export * from './${t}.slice';
280
280
  export * from './${t}.selectors';
281
281
  export * from './${t}.types';${e?`
282
282
  export * from './persist';`:""}
283
- `;await Z(Q.join(r,"index.ts"),o)};import{access as gr}from"node:fs/promises";import Xe from"node:path";var ze=async(t,r,e=Xe.join("src","store","slices"))=>{let o=Xe.join(t,e,r);try{return await gr(o),!0}catch{return!1}};var Je=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 o=process.cwd();e.persist&&e.noPersist===!0&&(v("Cannot use --persist and --no-persist together"),process.exit(1)),p($.cyan(`
283
+ `;await te(ie.join(i,"index.ts"),r)};import{access as Yi}from"node:fs/promises";import Ze from"node:path";var Qe=async(t,i,e=Ze.join("src","store","slices"))=>{let r=Ze.join(t,e,i);try{return await Yi(r),!0}catch{return!1}};var et=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(i,e)=>{try{let r=process.cwd();e.persist&&e.noPersist===!0&&(w("Cannot use --persist and --no-persist together"),process.exit(1)),p($.cyan(`
284
284
  \u{1F527} Slice Generator
285
- `)),h.start("Detecting project setup...");let s=await V(o);h.succeed("Project setup detected"),s.hasRedux||(h.fail("Redux is not setup in this project"),v("Please install @reduxjs/toolkit and react-redux first"),p($.dim(`
285
+ `)),h.start("Detecting project setup...");let s=await K(r);h.succeed("Project setup detected"),s.hasRedux||(h.fail("Redux is not setup in this project"),w("Please install @reduxjs/toolkit and react-redux first"),p($.dim(`
286
286
  Run: npm install @reduxjs/toolkit react-redux
287
287
  `)),process.exit(1)),p($.dim(` Redux: \u2713
288
- `));let i=await Ue(r,e.persist,e.noPersist===!0?!1:void 0),n,c,m;if(e.path){let C=e.path.replace(/^src\//,"");C.startsWith("features/")?(c=C.split("/")[1],n=G.join("src","features",c,"store"),m=G.join(o,n,i.sliceName)):(n=G.join("src",C),c=C.split("/")[0],m=G.join(o,n,i.sliceName))}else c=i.sliceName,n=G.join("src","features",c,"store"),m=G.join(o,n,i.sliceName);let g=G.join(o,n);hr(g)||await xr(g,{recursive:!0}),await ze(o,i.sliceName,n)&&(v(`Slice '${i.sliceName}' already exists at ${n}!`),process.exit(1)),h.start("Generating slice files..."),await He({sliceName:i.sliceName,slicePath:m,persistSlice:i.persistSlice}),h.succeed("Slice files generated"),h.start("Registering slice in rootReducer..."),await Ge(o,i.sliceName,i.persistSlice,n),h.succeed("Slice registered in rootReducer");let y=G.join(n,i.sliceName);p($.green(`
289
- \u2728 Slice '${i.sliceName}' created successfully!
290
- `)),p($.dim("Generated files:")),p($.dim(` \u{1F4C2} ${y}/`)),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 E=n.replace(/^src\//,"@/");p($.dim(` 1. Import actions: import { setLoading, setError } from '${E}/${i.sliceName}'`)),p($.dim(" 2. Use in component: dispatch(setLoading(true))")),p("")}catch(o){h.fail("Slice generation failed"),v(`${o}`),process.exit(1)}})};import D from"picocolors";import J from"node:path";import{existsSync as wr}from"node:fs";import{mkdir as Er}from"node:fs/promises";import Ye from"enquirer";var Ve=async(t,r,e,o)=>{let s=t||(await Ye.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 r!==void 0?i="axios":e!==void 0?i="fetch":o==="axios"?i="axios":o==="fetch"?i="fetch":o==="both"?i=(await Ye.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:i="axios",{serviceName:s,httpClient:i}};import{writeFile as Sr}from"node:fs/promises";import Pr from"node:path";var We=async t=>{await vr(t)},vr=async t=>{let{serviceName:r,servicePath:e,httpClient:o}=t,s=O(r),i;o==="axios"?i=`import { AppApis } from '@/lib/config';
288
+ `));let o=await qe(i,e.persist,e.noPersist===!0?!1:void 0),n,c,d;if(e.path){let E=e.path.replace(/^src\//,"");E.startsWith("features/")?(c=E.split("/")[1],n=J.join("src","features",c,"store"),d=J.join(r,n,o.sliceName)):(n=J.join("src",E),c=E.split("/")[0],d=J.join(r,n,o.sliceName))}else c=o.sliceName,n=J.join("src","features",c,"store"),d=J.join(r,n,o.sliceName);let g=J.join(r,n);Ji(g)||await zi(g,{recursive:!0}),await Qe(r,o.sliceName,n)&&(w(`Slice '${o.sliceName}' already exists at ${n}!`),process.exit(1)),h.start("Generating slice files..."),await Ke({sliceName:o.sliceName,slicePath:d,persistSlice:o.persistSlice}),h.succeed("Slice files generated"),h.start("Registering slice in rootReducer..."),await We(r,o.sliceName,o.persistSlice,n),h.succeed("Slice registered in rootReducer");let y=J.join(n,o.sliceName);p($.green(`
289
+ \u2728 Slice '${o.sliceName}' created successfully!
290
+ `)),p($.dim("Generated files:")),p($.dim(` \u{1F4C2} ${y}/`)),p($.dim(` \u251C\u2500\u2500 ${o.sliceName}.slice.ts`)),p($.dim(` \u251C\u2500\u2500 ${o.sliceName}.selectors.ts`)),o.persistSlice&&p($.dim(" \u251C\u2500\u2500 persist.ts")),p($.dim(` \u251C\u2500\u2500 ${o.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}/${o.sliceName}'`)),p($.dim(" 2. Use in component: dispatch(setLoading(true))")),p("")}catch(r){h.fail("Slice generation failed"),w(`${r}`),process.exit(1)}})};import H from"picocolors";import B from"node:path";import{existsSync as Zi}from"node:fs";import{mkdir as Qi}from"node:fs/promises";import tt from"enquirer";var it=async(t,i,e,r)=>{let s=t||(await tt.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 i!==void 0?o="axios":e!==void 0?o="fetch":r==="axios"?o="axios":r==="fetch"?o="fetch":r==="both"?o=(await tt.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:o="axios",{serviceName:s,httpClient:o}};import{writeFile as Vi}from"node:fs/promises";import Wi from"node:path";var ot=async t=>{await Bi(t)},Bi=async t=>{let{serviceName:i,servicePath:e,httpClient:r}=t,s=b(i),o;r==="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,28 @@ export const ${s}Service = {
306
306
  return fetchClient.get<string>(AppApis.${s}.getAll);
307
307
  },
308
308
  };
309
- `;let n=`${r}.service.ts`;await Sr(Pr.join(e,n),i)};import{existsSync as yr}from"node:fs";import Cr from"node:path";var Ke=async(t,r,e)=>{let o=Cr.join(t,e,`${r}.service.ts`);return yr(o)};var Be=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 o=process.cwd();e.axios&&e.fetch&&(v("Cannot use --axios and --fetch together"),process.exit(1)),p(D.cyan(`
309
+ `;let n=`${i}.service.ts`;await Vi(Wi.join(e,n),o)};import{existsSync as qi}from"node:fs";import Ki from"node:path";var rt=async(t,i,e)=>{let r=Ki.join(t,e,`${i}.service.ts`);return qi(r)};var nt=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(i,e)=>{try{let r=process.cwd();e.axios&&e.fetch&&(w("Cannot use --axios and --fetch together"),process.exit(1)),p(H.cyan(`
310
310
  \u{1F527} Service Generator
311
- `)),h.start("Detecting project setup...");let s=await V(o);h.succeed("Project setup detected"),s.httpClient==="none"&&(h.fail("No HTTP client is setup in this project"),v("Please setup either AxiosClient or FetchClient first"),p(D.dim(`
311
+ `)),h.start("Detecting project setup...");let s=await K(r);h.succeed("Project setup detected"),s.httpClient==="none"&&(h.fail("No HTTP client is setup in this project"),w("Please setup either AxiosClient or FetchClient first"),p(H.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(D.dim(` HTTP Clients: ${i.join(", ")}
314
- `));let n=await Ve(r,e.axios,e.fetch,s.httpClient),c,m,g;if(e.path){let C=e.path.replace(/^src\//,"");C.startsWith("features/")?(m=C.split("/")[1],c=J.join("src","features",m,"services"),g=J.join(o,c)):(c=J.join("src",C),m=C.split("/")[0],g=J.join(o,c))}else m=n.serviceName,c=J.join("src","features",m,"services"),g=J.join(o,c);wr(g)||await Er(g,{recursive:!0}),await Ke(o,n.serviceName,c)&&(v(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),h.start("Generating service files..."),await We({serviceName:n.serviceName,servicePath:g,httpClient:n.httpClient}),h.succeed("Service files generated"),h.start("Registering API endpoints..."),await oe({serviceName:n.serviceName,projectPath:o}),h.succeed("API endpoints registered");let y=J.join(c,`${n.serviceName}.service.ts`);p(D.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"),p(H.dim(` HTTP Clients: ${o.join(", ")}
314
+ `));let n=await it(i,e.axios,e.fetch,s.httpClient),c,d,g;if(e.path){let E=e.path.replace(/^src\//,"");E.startsWith("features/")?(d=E.split("/")[1],c=B.join("src","features",d,"services"),g=B.join(r,c)):(c=B.join("src",E),d=E.split("/")[0],g=B.join(r,c))}else d=n.serviceName,c=B.join("src","features",d,"services"),g=B.join(r,c);Zi(g)||await Qi(g,{recursive:!0}),await rt(r,n.serviceName,c)&&(w(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),h.start("Generating service files..."),await ot({serviceName:n.serviceName,servicePath:g,httpClient:n.httpClient}),h.succeed("Service files generated"),h.start("Registering API endpoints..."),await le({serviceName:n.serviceName,projectPath:r}),h.succeed("API endpoints registered");let y=B.join(c,`${n.serviceName}.service.ts`);p(H.green(`
315
315
  \u2728 Service '${n.serviceName}' created successfully!
316
- `)),p(D.dim("Generated files:")),p(D.dim(` \u{1F4C4} ${y}
317
- `)),p(D.cyan("Next steps:"));let E=c.replace(/^src\//,"@/");p(D.dim(` 1. Import service: import { ${n.serviceName}Service } from '${E}/${n.serviceName}.service'`)),p(D.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),p("")}catch(o){h.fail("Service generation failed"),v(`${o}`),process.exit(1)}})};import M from"picocolors";import br from"enquirer";import Rr from"node:path";import Ir from"picocolors";import ee from"node:path";import qe from"node:path";var ne=async t=>{let r=[qe.join(t,a.ROOT_LAYOUT),qe.join(t,"src/app/[locale]/layout.tsx")];for(let e of r)if(d(e)&&(await u(e)).includes("<body"))return e;for(let e of r)if(d(e))return e;return""};var Ze=async t=>{let r=ee.join(t,a.THEME_PROVIDER),e=ee.join(t,a.GLOBALS_CSS),o=ee.join(t,"package.json");if(d(r))return{isSetup:!0,reason:"CustomThemeProvider.tsx exists"};if(d(o)){let s=JSON.parse(await u(o));if(s.dependencies&&s.dependencies["next-themes"]||s.devDependencies&&s.devDependencies["next-themes"])return{isSetup:!0,reason:"next-themes is installed"}}return d(e)&&(await u(e)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},Qe=async t=>{let r=ee.join(t,a.GLOBALS_CSS),e=ee.join(t,a.PROVIDERS_INDEX),o=await ne(t);if(!d(r)||!o||!d(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 o};import et from"node:path";import Tr from"degit";var tt=async(t,r)=>{r.text="Fetching assets from starter repo...",await Tr("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},rt=async(t,r)=>{let e=et.join(t,a.THEME_PROVIDER),o=et.join(r,"src/providers/CustomThemeProvider.tsx");await te(o,e)};import se from"node:path";var it=async t=>{let r=se.join(t,a.PROVIDERS_INDEX),e=await u(r);e.includes("CustomThemeProvider")||(e+=`export * from './CustomThemeProvider';
318
- `,await f(r,e))},ot=async t=>{let r=se.join(t,"src/providers/RootProvider.tsx");if(d(r)){let e=await u(r);e.includes("CustomThemeProvider")||(e=e.replace(/import \{ StoreProvider \} from '@\/providers';\n/,`import { StoreProvider, CustomThemeProvider } from '@/providers';
316
+ `)),p(H.dim("Generated files:")),p(H.dim(` \u{1F4C4} ${y}
317
+ `)),p(H.cyan("Next steps:"));let T=c.replace(/^src\//,"@/");p(H.dim(` 1. Import service: import { ${n.serviceName}Service } from '${T}/${n.serviceName}.service'`)),p(H.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),p("")}catch(r){h.fail("Service generation failed"),w(`${r}`),process.exit(1)}})};import fe from"picocolors";import fo from"enquirer";import to from"node:path";import io from"picocolors";import oe from"node:path";import st from"node:path";var pe=async t=>{let i=[st.join(t,a.ROOT_LAYOUT),st.join(t,"src/app/[locale]/layout.tsx")];for(let e of i)if(l(e)&&(await m(e)).includes("<body"))return e;for(let e of i)if(l(e))return e;return""};var at=async t=>{let i=oe.join(t,a.THEME_PROVIDER),e=oe.join(t,a.GLOBALS_CSS),r=oe.join(t,"package.json");if(l(i))return{isSetup:!0,reason:"CustomThemeProvider.tsx exists"};if(l(r)){let s=JSON.parse(await m(r));if(s.dependencies&&s.dependencies["next-themes"]||s.devDependencies&&s.devDependencies["next-themes"])return{isSetup:!0,reason:"next-themes is installed"}}return l(e)&&(await m(e)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},ct=async t=>{let i=oe.join(t,a.GLOBALS_CSS),e=oe.join(t,a.PROVIDERS_INDEX),r=await pe(t);if(!l(i)||!r||!l(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 r};import lt from"node:path";import eo from"degit";var pt=async(t,i)=>{i.text="Fetching assets from starter repo...",await eo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},mt=async(t,i)=>{let e=lt.join(t,a.THEME_PROVIDER),r=lt.join(i,"src/providers/CustomThemeProvider.tsx");await _(r,e)};import me from"node:path";var dt=async t=>{let i=me.join(t,a.PROVIDERS_INDEX),e=await m(i);e.includes("CustomThemeProvider")||(e+=`export * from './CustomThemeProvider';
318
+ `,await u(i,e))},ut=async t=>{let i=me.join(t,"src/providers/RootProvider.tsx");if(l(i)){let e=await m(i),r="'use client';",s=e.includes(r);if(s&&(e=e.replace(r,"").trim()),e.includes("CustomThemeProvider")||(e=e.replace(/import \{ StoreProvider \} from '@\/providers';\n/,`import { StoreProvider, CustomThemeProvider } from '@/providers';
319
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>
320
+ `+e)),s&&(e=r+`
321
+ `+e),!e.includes("<CustomThemeProvider>")){if(e.includes("<StoreProvider>"))e=e.replace(/<StoreProvider>/,`<StoreProvider>
321
322
  <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,i,n,c)=>`return (
323
+ </StoreProvider>`);else{let o=e.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];e=e.replace(o[0],`return (
323
324
  <CustomThemeProvider>
324
- <${i}${n}>${c}</${i}>
325
+ ${n}
325
326
  </CustomThemeProvider>
326
- );`)),await f(r,e))}},nt=async(t,r)=>{let e=se.join(t,a.GLOBALS_CSS),o=se.join(r,"src/styles/globals.css"),s="";if(d(o)){let n=await u(o),c=n.match(/@custom-variant dark \(.*?\);/),m=n.match(/@theme \{[\s\S]*?\}/);c&&(s+=`
327
+ );`)}}await u(i,e)}}},ft=async(t,i)=>{let e=me.join(t,a.GLOBALS_CSS),r=me.join(i,"src/styles/globals.css"),s="";if(l(r)){let n=await m(r),c=n.match(/@custom-variant dark \(.*?\);/),d=n.match(/@theme \{[\s\S]*?\}/);c&&(s+=`
327
328
  ${c[0]}
328
- `),m&&(s+=`
329
- ${m[0]}
329
+ `),d&&(s+=`
330
+ ${d[0]}
330
331
  `)}s||(s=`
331
332
  @custom-variant dark (&:where(.dark, .dark *));
332
333
 
@@ -334,23 +335,87 @@ ${m[0]}
334
335
  --color-dark: #202938;
335
336
  --color-light: #f5f5f5;
336
337
  }
337
- `);let i=await u(e);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 f(e,i)}},st=async t=>{let r=await u(t);r.includes("dark:bg-dark")||(r=r.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await f(t,r))};var he=async t=>{let r=b("Setting up Dark Theme..."),e=Rr.join(t,".next-maker-temp");try{let{isSetup:o,reason:s}=await Ze(t);if(o){r.fail(`Dark Theme is already set up (${s}).`);return}let i=await Qe(t);await tt(e,r),await rt(t,e),await it(t),await ot(t),await nt(t,e),await st(i),r.text="Installing next-themes...",await X(t,"next-themes"),r.text="Formatting code...";let n=await K(t);await H(t,n,"format"),r.succeed(Ir.green("Dark Theme setup successfully!"))}catch(o){throw r.fail("Failed to setup Dark Theme."),o}finally{await S(e)}};import $r from"node:path";import Or from"picocolors";import xe from"node:path";var at=async t=>{let r=xe.join(t,a.STORE),e=xe.join(t,"package.json");if(d(r))return{isSetup:!0,reason:"src/store directory exists"};if(d(e)){let o=JSON.parse(await u(e));if(o.dependencies&&o.dependencies["@reduxjs/toolkit"]||o.devDependencies&&o.devDependencies["@reduxjs/toolkit"])return{isSetup:!0,reason:"@reduxjs/toolkit is installed"}}return{isSetup:!1,reason:""}},ct=async t=>{let r=xe.join(t,a.PROVIDERS_INDEX);if(!await ne(t)||!d(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 Y from"node:path";import Nr from"degit";import pt from"node:fs/promises";var mt=async(t,r)=>{r.text="Fetching assets from starter repo...",await Nr("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},lt=async(t,r)=>{let e=Y.join(r,"src/providers/StoreProvider.tsx"),o=Y.join(t,a.STORE_PROVIDER);await te(e,o);let s=Y.join(r,"src/store"),i=Y.join(t,a.STORE);await pt.cp(s,i,{recursive:!0})},dt=async(t,r)=>{let e=Y.join(r,"src/features/counter"),o=Y.join(t,a.COUNTER_FEATURE);await pt.cp(e,o,{recursive:!0});let s=Y.join(o,"components/Counter.tsx");if(await d(s)){let i=await u(s);i=i.replace(/import \{ useTranslations \} from 'next-intl';\n?/,""),i=i.replace(/const t = useTranslations\('Count'\);\n?/,""),i=i.replace(/\{t\('currentCount', \{ count: value \}\)\}/g,"Current Count: {value}"),i=i.replace(/\{t\('increment'\)\}/g,"Increment"),i=i.replace(/\{t\('decrement'\)\}/g,"Decrement"),i=i.replace(/\{t\('reset'\)\}/g,"Reset"),await f(s,i)}};import ae from"node:path";var ut=async t=>{let r=ae.join(t,a.PROVIDERS_INDEX),e=await u(r);e.includes("StoreProvider")||(e+=`export * from './StoreProvider';
339
- `,await f(r,e))},ft=async t=>{let r=ae.join(t,"src/providers/RootProvider.tsx");if(d(r)){let e=await u(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,i,n,c)=>`return (
338
+ `);let o=await m(e);if(!o.includes("@custom-variant dark")){if(o.includes("@import")){let n=o.lastIndexOf("@import"),c=o.indexOf(`
339
+ `,n);o=o.slice(0,c+1)+s+o.slice(c+1)}else o=s+o;await u(e,o)}},gt=async t=>{let i=await m(t);i.includes("dark:bg-dark")||(i=i.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await u(t,i))};var we=async t=>{let i=R("Setting up Dark Theme..."),e=to.join(t,".next-maker-temp");try{let{isSetup:r,reason:s}=await at(t);if(r){i.fail(`Dark Theme is already set up (${s}).`);return}let o=await ct(t);await pt(e,i),await mt(t,e),await dt(t),await ut(t),await ft(t,e),await gt(o),i.text="Installing next-themes...",await F(t,"next-themes"),i.text="Formatting code...";let n=await M(t);await j(t,n,"format"),i.succeed(io.green("Dark Theme setup successfully!"))}catch(r){throw i.fail("Failed to setup Dark Theme."),r}finally{await x(e)}};import ro from"node:path";import no from"picocolors";import Te from"node:path";var xt=async t=>{let i=Te.join(t,a.STORE),e=Te.join(t,"package.json");if(l(i))return{isSetup:!0,reason:"src/store directory exists"};if(l(e)){let r=JSON.parse(await m(e));if(r.dependencies&&r.dependencies["@reduxjs/toolkit"]||r.devDependencies&&r.devDependencies["@reduxjs/toolkit"])return{isSetup:!0,reason:"@reduxjs/toolkit is installed"}}return{isSetup:!1,reason:""}},ht=async t=>{let i=Te.join(t,a.PROVIDERS_INDEX);if(!await pe(t)||!l(i))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx (or src/app/[locale]/layout.tsx) and src/providers/index.ts exist.")};import q from"node:path";import oo from"degit";import Pt from"node:fs/promises";var yt=async(t,i)=>{i.text="Fetching assets from starter repo...",await oo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},St=async(t,i)=>{let e=q.join(i,"src/providers/StoreProvider.tsx"),r=q.join(t,a.STORE_PROVIDER);await _(e,r);let s=q.join(i,"src/store"),o=q.join(t,a.STORE);await Pt.cp(s,o,{recursive:!0})},vt=async(t,i)=>{let e=q.join(i,"src/features/counter"),r=q.join(t,a.COUNTER_FEATURE);await Pt.cp(e,r,{recursive:!0});let s=q.join(r,"components/Counter.tsx");if(await l(s)){let o=await m(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 de from"node:path";var Ct=async t=>{let i=de.join(t,a.PROVIDERS_INDEX),e=await m(i);e.includes("StoreProvider")||(e+=`export * from './StoreProvider';
340
+ `,await u(i,e))},wt=async t=>{let i=de.join(t,"src/providers/RootProvider.tsx");if(l(i)){let e=await m(i),r="'use client';",s=e.includes(r);if(s&&(e=e.replace(r,"").trim()),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';
341
+ `+e)),s&&(e=r+`
342
+ `+e),!e.includes("<StoreProvider>")){let o=e.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];e=e.replace(o[0],`return (
341
343
  <StoreProvider>
342
- <${i}${n}>${c}</${i}>
344
+ ${n}
343
345
  </StoreProvider>
344
- );`),await f(r,e))}},gt=async t=>{let r=[ae.join(t,a.ROOT_PAGE),ae.join(t,"src/app/[locale]/page.tsx")],e="";for(let o of r)if(d(o)){e=o;break}if(e){let o=await u(e);if(o.includes("Counter")||(o=`import { Counter } from '@/features/counter/components/Counter';
345
- `+o),!o.includes("<Counter />")){let s=o.lastIndexOf("</div>"),i=o.lastIndexOf("</main>"),n=i!==-1?i:s;n!==-1&&(o=o.slice(0,n)+`
346
+ );`),await u(i,e)}}}},Tt=async t=>{let i=[de.join(t,a.ROOT_PAGE),de.join(t,"src/app/[locale]/page.tsx")],e="";for(let r of i)if(l(r)){e=r;break}if(e){let r=await m(e);if(r.includes("Counter")||(r=`import { Counter } from '@/features/counter/components/Counter';
347
+ `+r),!r.includes("<Counter />")){let s=r.lastIndexOf("</div>"),o=r.lastIndexOf("</main>"),n=o!==-1?o:s;n!==-1&&(r=r.slice(0,n)+`
346
348
  <div className="mt-8">
347
349
  <h2 className="text-2xl font-bold mb-4">Redux Counter</h2>
348
350
  <Counter />
349
351
  </div>
350
- `+o.slice(n),await f(e,o))}}};var Se=async t=>{let r=b("Setting up Redux Toolkit..."),e=$r.join(t,".next-maker-temp-redux");try{let{isSetup:o,reason:s}=await at(t);if(o){r.fail(`Redux is already set up (${s}).`);return}await ct(t),await mt(e,r),r.text="Copying Redux files...",await lt(t,e),r.text="Creating Counter feature...",await dt(t,e),r.text="Updating providers and pages...",await ut(t),await ft(t),await gt(t),r.text="Installing dependencies...",await X(t,"@reduxjs/toolkit"),await X(t,"react-redux"),await X(t,"redux-persist"),await X(t,"react-secure-storage"),r.text="Formatting code...";let i=await K(t);await H(t,i,"format"),r.succeed(Or.green("Redux Toolkit setup successfully!"))}catch(o){throw r.fail("Failed to setup Redux Toolkit."),o}finally{await S(e)}};var{prompt:Ar}=br,ht=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{p(M.cyan(`
352
+ `+r.slice(n),await u(e,r))}}};var Ee=async t=>{let i=R("Setting up Redux Toolkit..."),e=ro.join(t,".next-maker-temp-redux");try{let{isSetup:r,reason:s}=await xt(t);if(r){i.fail(`Redux is already set up (${s}).`);return}await ht(t),await yt(e,i),i.text="Copying Redux files...",await St(t,e),i.text="Creating Counter feature...",await vt(t,e),i.text="Updating providers and pages...",await Ct(t),await wt(t),await Tt(t),i.text="Installing dependencies...",await F(t,"@reduxjs/toolkit"),await F(t,"react-redux"),await F(t,"redux-persist"),await F(t,"react-secure-storage"),i.text="Formatting code...";let o=await M(t);await j(t,o,"format"),i.succeed(no.green("Redux Toolkit setup successfully!"))}catch(r){throw i.fail("Failed to setup Redux Toolkit."),r}finally{await x(e)}};import lo from"node:path";import po from"picocolors";import ue from"node:path";var Et=async t=>{let i=ue.join(t,a.I18N_DIR),e=ue.join(t,"package.json");if(l(i))return{isSetup:!0,reason:"src/i18n directory exists"};if(l(e)){let r=JSON.parse(await m(e));if(r.dependencies&&r.dependencies["next-intl"]||r.devDependencies&&r.devDependencies["next-intl"])return{isSetup:!0,reason:"next-intl is installed"}}return{isSetup:!1,reason:""}},It=async t=>{let i=ue.join(t,a.ROOT_LAYOUT),e=ue.join(t,"src/app/[locale]/layout.tsx");if(!l(i)&&!l(e))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx exists.")};import z from"node:path";import so from"degit";import ao from"node:fs/promises";var Rt=async(t,i)=>{i.text="Fetching assets from starter repo...",await so("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},Nt=async(t,i)=>{let e=z.join(i,"src/i18n"),r=z.join(t,a.I18N_DIR);await ao.cp(e,r,{recursive:!0});let s=z.join(i,"src/proxy.ts"),o=z.join(t,a.PROXY);await _(s,o);let n=z.join(i,"src/types/i18n.ts"),c=z.join(t,a.I18N_TYPES);await _(n,c);let d=z.join(i,"src/lib/config/app-locales.ts"),g=z.join(t,a.APP_LOCALES);await _(d,g)};import U from"node:path";import co from"node:fs/promises";var Ot=async t=>{let i=U.join(t,a.NEXT_CONFIG);if(l(i)){let e=await m(i);if(!e.includes("createNextIntlPlugin")){e=`import createNextIntlPlugin from 'next-intl/plugin';
353
+ `+e;let r=/export default (.*?);/;r.test(e)?e=e.replace(r,`
354
+ const withNextIntl = createNextIntlPlugin();
355
+ export default withNextIntl($1);`):(e+=`
356
+ const withNextIntl = createNextIntlPlugin();
357
+ `,e+=`export default withNextIntl(nextConfig);
358
+ `),await u(i,e)}}},At=async t=>{let i=U.join(t,a.TYPES_INDEX);if(l(i)){let e=await m(i);e.includes("./i18n")||(e+=`export * from './i18n';
359
+ `,await u(i,e))}},$t=async t=>{let i=U.join(t,a.CONFIG_INDEX);if(l(i)){let e=await m(i);e.includes("./app-locales")||(e+=`export * from './app-locales';
360
+ `,await u(i,e))}},bt=async t=>{let i=U.join(t,"src/providers/RootProvider.tsx");if(l(i)){let e=await m(i),r="'use client';",s=e.includes(r);if(s&&(e=e.replace(r,"").trim()),e.includes("next-intl")||(e=`import { SupportedLocale } from '@/types/i18n';
361
+ import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';
362
+ `+e),s&&(e=r+`
363
+ `+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 = ({
364
+ children,
365
+ locale,
366
+ messages,
367
+ }: {
368
+ children: React.ReactNode;
369
+ locale: SupportedLocale;
370
+ messages: AbstractIntlMessages;
371
+ }) => {`))}if(!e.includes("<NextIntlClientProvider")){let o=e.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];if(n.includes("{children}")){let c=n.replace("{children}",`<NextIntlClientProvider locale={locale} messages={messages}>
372
+ {children}
373
+ </NextIntlClientProvider>`);e=e.replace(o[0],`return (
374
+ ${c}
375
+ );`)}else e=e.replace(o[0],`return (
376
+ <NextIntlClientProvider locale={locale} messages={messages}>
377
+ ${n}
378
+ </NextIntlClientProvider>
379
+ );`)}}await u(i,e)}},_t=async t=>{let i=U.join(t,a.ROOT_LAYOUT),e=U.join(t,a.ROOT_PAGE),r=U.join(t,"src/app/[locale]");if(await co.mkdir(r,{recursive:!0}),l(i)){let s=U.join(r,"layout.tsx"),o=await m(i);if(o.includes("next-intl")||(o=`import { routing } from '@/i18n/routing';
380
+ import { hasLocale } from 'next-intl';
381
+ import { notFound } from 'next/navigation';
382
+ import { setRequestLocale, getMessages } from 'next-intl/server';
383
+ `+o),!o.includes("generateStaticParams")){let d=o.indexOf("};",o.indexOf("export const metadata"));if(d!==-1){let g=d+2;o=o.slice(0,g)+`
384
+
385
+ export function generateStaticParams() {
386
+ return routing.locales.map((locale) => ({ locale }));
387
+ }`+o.slice(g)}}o=o.replace(/Readonly<\{\s*children:\s*React\.ReactNode;\s*}>/,`Readonly<{
388
+ children: React.ReactNode;
389
+ params: Promise<{ locale: string }>;
390
+ }>`);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*\{/,C=o.match(g);if(C&&C.index!==void 0){let y=C.index+C[0].length-1;o=o.slice(0,y+1)+`
391
+ const { locale } = await params;
392
+
393
+ if (!hasLocale(routing.locales, locale)) {
394
+ notFound();
395
+ }
396
+
397
+ setRequestLocale(locale);
398
+
399
+ const messages = await getMessages();
400
+ `+o.slice(y+1)}o=o.replace(/<RootProvider>/,"<RootProvider locale={locale} messages={messages}>"),o=o.replace(/<html lang="en"/,"<html lang={locale}")}await u(s,o),await P(i)}if(l(e)){let s=U.join(r,"page.tsx"),o=await m(e);o.includes("next-intl")||(o=`import { SupportedLocale } from '@/types/i18n';
401
+ import { setRequestLocale } from 'next-intl/server';
402
+ `+o),o=o.replace(/export default function Home\(\)/,`type Props = {
403
+ params: Promise<{ locale: string }>;
404
+ };
405
+
406
+ export default async function Home(props: Props)`);let n=o.indexOf("export default async function Home(props: Props) {");if(n!==-1){let c=`
407
+ const locale = (await props.params).locale as SupportedLocale;
408
+ setRequestLocale(locale);
409
+ `,d=o.indexOf("{",n);o=o.slice(0,d+1)+c+o.slice(d+1)}await u(s,o),await P(e)}};var Ie=async t=>{let i=R("Setting up Internationalization (next-intl)..."),e=lo.join(t,".next-maker-temp-i18n");try{let{isSetup:r,reason:s}=await Et(t);if(r){i.fail(`i18n is already set up (${s}).`);return}await It(t),await Rt(e,i),i.text="Copying i18n files...",await Nt(t,e),i.text="Configuring project structure...",await Ot(t),await At(t),await $t(t),await bt(t),i.text="Migrating to [locale] structure...",await _t(t),i.text="Installing dependencies...",await F(t,"next-intl"),i.text="Formatting code...";let o=await M(t);await j(t,o,"format"),i.succeed(po.green("Internationalization setup successfully!"))}catch(r){throw i.fail("Failed to setup Internationalization."),r}finally{await x(e)}};import uo from"node:path";import Xt from"picocolors";import Yt from"enquirer";import re from"node:path";var jt=async t=>{let i=re.join(t,a.FETCH_CLIENT),e=re.join(t,a.AXIOS_CLIENT),r=l(i),s=l(e);return r&&s?{status:"both",reason:"Both Fetch and Axios clients are detected"}:r?{status:"fetch",reason:"Fetch client is already setup"}:s?{status:"axios",reason:"Axios client is already setup"}:{status:"none"}},Ft=async t=>{let e=[re.join(t,"src/lib"),re.join(t,"src/types"),re.join(t,"src/lib/config")].filter(r=>!l(r));if(e.length>0)throw new Error(`Invalid project structure. Missing directories:
410
+ ${e.map(r=>`- ${r}`).join(`
411
+ `)}`)};import v from"node:path";import mo from"degit";import ne from"node:fs/promises";var kt=async(t,i)=>{i.text="Downloading assets from starter repository...",await mo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(t)},Dt=async(t,i,e)=>{let r=v.join(t,a.HTTP_UTILS),s=v.join(i,a.HTTP_UTILS);await ne.cp(v.join(i,a.ERRORS_DIR),v.join(t,a.ERRORS_DIR),{recursive:!0}),await _(v.join(i,a.APP_APIS),v.join(t,a.APP_APIS)),await ne.cp(v.join(i,a.COMMON_TYPES_DIR),v.join(t,a.COMMON_TYPES_DIR),{recursive:!0}),await ne.cp(v.join(i,a.UTILITY_TYPES_DIR),v.join(t,a.UTILITY_TYPES_DIR),{recursive:!0}),e==="fetch"?(await ne.cp(v.join(i,a.FETCH_CLIENT),v.join(t,a.FETCH_CLIENT),{recursive:!0}),await x(v.join(t,a.AXIOS_CLIENT))):(await ne.cp(v.join(i,a.AXIOS_CLIENT),v.join(t,a.AXIOS_CLIENT),{recursive:!0}),await x(v.join(t,a.FETCH_CLIENT))),await _(v.join(s,"index.ts"),v.join(r,"index.ts")),await _(v.join(i,a.HTTP_TYPES),v.join(t,a.HTTP_TYPES))};import se from"node:path";var Lt=async(t,i)=>{let e=se.join(t,a.HTTP_UTILS,"index.ts");if(l(e)){let r=await m(e);i==="fetch"?(r=r.replace(/export .* from '\.\/axios-client';\n?/g,""),r.includes("fetch-client")||(r+=`export * from './fetch-client';
412
+ `)):(r=r.replace(/export .* from '\.\/fetch-client';\n?/g,""),r.includes("axios-client")||(r+=`export * from './axios-client';
413
+ `)),await u(e,r)}},Mt=async(t,i)=>{let e=se.join(t,a.HTTP_TYPES);if(l(e)){let r=await m(e);i==="fetch"?(r=r.replace(/declare module 'axios' \{[\s\S]*?\}\n\n?/g,""),r=r.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n?/g,"")):(r=r.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n?/g,""),r=r.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n?/g,"")),await u(e,r)}},Gt=async t=>{let i=se.join(t,a.UTILS_INDEX);if(l(i)){let e=await m(i);e.includes("./http")||(e+=`export * from './http';
414
+ `,await u(i,e))}},Ht=async t=>{let i=se.join(t,a.TYPES_INDEX);if(l(i)){let e=await m(i);e.includes("./common")||(e+=`export * from './common';
415
+ `),e.includes("./utility")||(e+=`export * from './utility';
416
+ `),await u(i,e)}},Ut=async t=>{let i=se.join(t,a.CONFIG_INDEX);if(l(i)){let e=await m(i);e.includes("./app-apis")||(e+=`export * from './app-apis';
417
+ `,await u(i,e))}};var Re=async t=>{let i=R("Checking HTTP Client setup..."),e=uo.join(t,".next-maker-temp-http");try{let{status:r,reason:s}=await jt(t);i.stop();let o="fetch";if(r==="both"){console.log(Xt.red(`\u2716 ${s}`));return}if(r!=="none"){let{action:c}=await Yt.prompt({type:"select",name:"action",message:`${s}. What would you like to do?`,choices:[{name:"cancel",message:"Cancel"},{name:"switch",message:`Switch to ${r==="fetch"?"Axios":"Fetch"}`}]});if(c==="cancel")return;o=r==="fetch"?"axios":"fetch"}else{let{type:c}=await Yt.prompt({type:"select",name:"type",message:"Which HTTP client do you want to setup?",choices:[{name:"fetch",message:"Fetch (Native)"},{name:"axios",message:"Axios"}]});o=c}i.start(`Setting up ${o==="fetch"?"Fetch":"Axios"} client...`),await Ft(t),await kt(e,i),i.text="Copying client files...",await Dt(t,e,o),i.text="Configuring client...",await Lt(t,o),await Mt(t,o),await Gt(t),await Ht(t),await Ut(t),o==="axios"&&(i.text="Installing Axios...",await F(t,"axios")),i.text="Formatting code...";let n=await M(t);await j(t,n,"format"),i.succeed(Xt.green(`HTTP Client (${o}) setup successfully!`))}catch(r){throw i.fail("Failed to setup HTTP Client."),r}finally{await x(e)}};var{prompt:go}=fo,Jt=t=>{t.command("setup").description("Setup features in an existing Next.js project").option("--http-client","Setup HTTP client (axios|fetch)").option("--dark-theme","Setup Dark Theme (Tailwind + next-themes)").option("--redux","Setup Redux Toolkit").option("--i18n","Setup next-intl for internationalization").action(async i=>{try{if(p(fe.cyan(`
351
418
  \u{1F527} Setup Wizard
352
- `));let e;if(!r.httpClient&&!r.darkTheme&&!r.redux&&!r.i18n){if(e=(await Ar([{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"){p(M.yellow("Setup cancelled."));return}e==="Dark Theme"?await he(process.cwd()):e==="Redux Toolkit"?await Se(process.cwd()):(p(M.yellow(`
353
- \u26A0\uFE0F ${e} setup is not implemented yet.`)),p(M.dim("This feature will be available in a future update.")))}else r.httpClient&&(p(M.yellow(`
354
- \u26A0\uFE0F HTTP Client setup is not implemented yet.`)),p(M.dim("This feature will be available in a future update."))),r.darkTheme&&await he(process.cwd()),r.redux&&await Se(process.cwd()),r.i18n&&(p(M.yellow(`
355
- \u26A0\uFE0F Internationalization setup is not implemented yet.`)),p(M.dim("This feature will be available in a future update.")))}catch(e){h.fail("Setup failed"),v(`${e}`),process.exit(1)}})};var xt=t=>{Ae(t),ht(t),Me(t),Je(t),Be(t)};async function _r(){Ee({logger:r=>ie(r)});let t=new jr;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),xt(t),t.parse()}_r().catch(t=>{let r=t&&typeof t=="object"&&"message"in t?t.message:String(t);ie(`Unexpected error: ${r}`)});
419
+ `)),i.httpClient||i.darkTheme||i.redux||i.i18n){i.httpClient&&await Re(process.cwd()),i.darkTheme&&await we(process.cwd()),i.redux&&await Ee(process.cwd()),i.i18n&&await Ie(process.cwd());return}let r=(await go([{type:"select",name:"feature",message:"What would you like to setup?",choices:[{name:"Dark Theme",value:"dark-theme"},{name:"Redux Toolkit",value:"redux"},{name:"HTTP Client (Axios/Fetch)",value:"http-client"},{name:"Internationalization (next-intl)",value:"i18n"},"Cancel"]}])).feature;if(r==="Cancel"){p(fe.yellow("Setup cancelled."));return}r==="dark-theme"?await we(process.cwd()):r==="redux"?await Ee(process.cwd()):r==="http-client"?await Re(process.cwd()):r==="i18n"?await Ie(process.cwd()):(p(fe.yellow(`
420
+ \u26A0\uFE0F ${r} setup is not implemented yet.`)),p(fe.dim("This feature will be available in a future update.")))}catch(e){h.fail("Setup failed"),w(`${e}`),process.exit(1)}})};var zt=t=>{He(t),Jt(t),Be(t),et(t),nt(t)};async function ho(){_e({logger:i=>ce(i)});let t=new xo;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),zt(t),t.parse()}ho().catch(t=>{let i=t&&typeof t=="object"&&"message"in t?t.message:String(t);ce(`Unexpected error: ${i}`)});
356
421
  //# sourceMappingURL=index.js.map