@teispace/next-maker 0.4.0 → 1.0.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 Yt}from"commander";import ie from"node:path";import L from"picocolors";import Me from"ora";function D(t="",e){let i=Me({text:t,...e});return i.start(),i}import Ue from"enquirer";var{prompt:He}=Ue,se=async t=>{let e=await He([{type:"input",name:"projectName",message:"What is the project name?",initial:t||"my-app",skip:!!t,validate:i=>/^[a-z0-9-_]+$/.test(i)?!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:i=>/^\d+\.\d+\.\d+$/.test(i)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:i=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(i)?!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:i=>{if(!i)return!0;let n=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!n.test(i)&&!s.test(i)?"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 i=this.state?.answers??this.enquirer?.answers??{};return!!(i.httpClient&&i.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:i=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(i)?!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:i=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(i)?!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:i=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(i)?!0:"Invalid Docker image tag."},{type:"confirm",name:"ci",message:"Do you want to include GitHub Actions (CI/CD)?",initial:!1},{type:"confirm",name:"preCommitHooks",message:"Do you want to setup pre-commit hooks (Husky, Commitlint, Lint-staged)?",initial:!0},{type:"confirm",name:"commitizen",message:"Do you want to setup Commitizen?",initial:!0},{type:"confirm",name:"copyEnv",message:"Want to copy .env.example to .env?",initial:!0}]);if(e.company=e.author,e.gitRemote&&!e.gitHomepage){let i=e.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");e.gitHomepage=`${i}#readme`,e.gitIssues=`${i}/issues`}return e};import X from"node:fs/promises";import Xe from"node:path";import{existsSync as Q}from"node:fs";var g=async t=>X.readFile(t,"utf-8"),u=async(t,e)=>{await X.mkdir(Xe.dirname(t),{recursive:!0}),await X.writeFile(t,e,"utf-8")},h=async t=>{Q(t)&&await X.unlink(t)},y=async t=>{Q(t)&&await X.rm(t,{recursive:!0,force:!0})},z=async(t,e)=>{let i=await g(t),n=JSON.parse(i),s=e(n);await u(t,JSON.stringify(s,null,2))},x=t=>Q(t);import{exec as ze}from"node:child_process";import{promisify as Ye}from"node:util";var B=Ye(ze),ae=async t=>{try{await B("git init",{cwd:t}),await B("git add .",{cwd:t}),await B('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t})}catch(e){console.warn("Failed to initialize git repository",e)}},ce=async(t,e)=>{try{await B(`git remote add origin ${e}`,{cwd:t})}catch(i){console.warn("Failed to add remote origin",i)}};import{exec as We}from"node:child_process";import{promisify as Ke}from"node:util";var pe=Ke(We),le=async(t,e)=>{let i=`${e} install`;try{await pe(i,{cwd:t})}catch(n){throw new Error(`Failed to install dependencies with ${e}: ${n}`)}},ee=async(t,e,i)=>{let n=e==="npm"?`${e} run ${i}`:`${e} ${i}`;try{await pe(n,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${i}': ${s}`)}};import A from"picocolors";var Ve={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 M(t,e="reset"){let i=Ve[e]??(n=>n);console.log(i(t))}function J(t){M(`\u2716 ${t}`,"red")}var E=J;function p(t){M(t)}function me(){console.log(""),M("\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"),M("\u2551 \u2551","cyan"),M("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),M("\u2551 \u2551","cyan"),M("\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 de(t){let{logger:e=o=>console.error(o),exitOnCancel:i=process.env.NODE_ENV!=="test"}=t??{},n=()=>{console.log(""),console.log(""),e("Setup cancelled by user"),console.log(""),i&&process.exit(0)},s=o=>{if(o!==null&&typeof o=="object"&&"code"in o&&o.code==="ERR_USE_AFTER_CLOSE"){n();return}if(o instanceof Error){e(`Uncaught exception: ${o.message}`);return}e(`Uncaught exception: ${String(o)}`)},r=o=>{if(o instanceof Error){e(`Unhandled promise rejection: ${o.message}`);return}e(`Unhandled promise rejection: ${String(o)}`)};return process.on("SIGINT",n),process.on("SIGTERM",n),process.on("uncaughtException",s),process.on("unhandledRejection",r),()=>{process.off("SIGINT",n),process.off("SIGTERM",n),process.off("uncaughtException",s),process.off("unhandledRejection",r)}}var Be=t=>t.charAt(0).toUpperCase()+t.slice(1),O=t=>t.replace(/-([a-z])/g,(e,i)=>i.toUpperCase()),G=t=>Be(O(t));import Je from"ora";var f=Je();import qe from"degit";var ue=async t=>{let e=D("Downloading template...");try{await qe("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(t),e.succeed("Template downloaded successfully.")}catch(i){throw e.fail("Failed to download template."),i}};import Ze from"node:path";var a={NEXT_CONFIG:"next.config.ts",TAILWIND_CONFIG:"tailwind.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",ESLINT_CONFIG:"eslint.config.mjs",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md"};var w={REDUX_TOOLKIT:"@reduxjs/toolkit",REACT_REDUX:"react-redux",REDUX_PERSIST:"redux-persist",REACT_SECURE_STORAGE:"react-secure-storage",NEXT_INTL:"next-intl",NEXT_THEMES:"next-themes",AXIOS:"axios",HUSKY:"husky",COMMITLINT_CLI:"@commitlint/cli",COMMITLINT_CONFIG:"@commitlint/config-conventional",LINT_STAGED:"lint-staged",COMMITIZEN:"commitizen",CZ_CONVENTIONAL_CHANGELOG:"cz-conventional-changelog"};var fe=async(t,e)=>{let i=D("Configuring package.json...");try{let n=e.gitRemote,s=e.gitHomepage,r=e.gitIssues;e.gitRemote&&(e.gitRemote.startsWith("git@github.com:")&&(n=e.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"")),s||(s=`${n.replace(/\.git$/,"")}#readme`),r||(r=`${n.replace(/\.git$/,"")}/issues`),n.endsWith(".git")||(n=`${n}.git`)),await z(Ze.join(t,a.PACKAGE_JSON),o=>(o.name=e.projectName,o.version=e.version,o.description=e.description,o.author=e.author,delete o.packageManager,s&&(o.homepage=s),r&&(o.bugs={url:r}),n&&(o.repository={type:"git",url:n}),e.redux||(delete o.dependencies[w.REDUX_TOOLKIT],delete o.dependencies[w.REACT_REDUX],delete o.dependencies[w.REDUX_PERSIST]),e.httpClient!=="none"||e.reactSecureStorage||delete o.dependencies[w.REACT_SECURE_STORAGE],e.i18n||delete o.dependencies[w.NEXT_INTL],e.darkMode||delete o.dependencies[w.NEXT_THEMES],e.httpClient==="none"?delete o.dependencies[w.AXIOS]:e.httpClient==="fetch"&&delete o.dependencies[w.AXIOS],o)),i.succeed("package.json configured.")}catch(n){throw i.fail("Failed to configure package.json."),n}};import l from"node:path";var ge=async(t,e)=>{let i=D("Customizing features...");try{await Qe(t,e),await et(t,e),await tt(t,e),await it(t,e),await rt(t,e),await ot(t),await nt(t),await st(t),i.succeed("Features customized.")}catch(n){throw i.fail("Failed to customize features."),n}},Qe=async(t,e)=>{let i=l.join(t,a.HTTP_UTILS),n=e.httpClient!=="none"||e.reactSecureStorage;if(e.httpClient==="none"){if(await y(l.join(t,a.AXIOS_CLIENT)),await y(l.join(t,a.FETCH_CLIENT)),n)await u(l.join(i,"index.ts"),`export * from './token-store';
3
- `),await h(l.join(t,a.CLIENT_UTILS));else{await y(i);let r=l.join(t,a.UTILS_INDEX);if(x(r)){let c=await g(r);c=c.replace(/export \* from '\.\/http';\n/,""),await u(r,c)}await h(l.join(t,a.APP_APIS));let o=l.join(t,a.CONFIG_INDEX);if(x(o)){let c=await g(o);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await u(o,c)}}let s=l.join(t,a.CONSTANTS);if(x(s)){let r=await g(s);r=r.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),r=r.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await u(s,r)}if(await y(l.join(t,a.ERRORS_DIR)),!n){await y(l.join(t,a.COMMON_TYPES_DIR)),await y(l.join(t,a.UTILITY_TYPES_DIR));let r=l.join(t,a.TYPES_INDEX);if(x(r)){let o=await g(r);o=o.replace(/export \* from '\.\/utility';\n/,""),o=o.replace(/export \* from '\.\/common';\n/,""),await u(r,o)}}}else if(e.httpClient==="axios"){await y(l.join(t,a.FETCH_CLIENT));let s=await g(l.join(i,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await u(l.join(i,"index.ts"),s);let r=l.join(t,a.HTTP_TYPES);if(x(r)){let o=await g(r);o=o.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),o=o.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await u(r,o)}}else if(e.httpClient==="fetch"){await y(l.join(t,a.AXIOS_CLIENT));let s=await g(l.join(i,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await u(l.join(i,"index.ts"),s);let r=l.join(t,a.HTTP_TYPES);if(x(r)){let o=await g(r);o=o.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),o=o.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await u(r,o)}}},et=async(t,e)=>{e.httpClient!=="none"||e.reactSecureStorage||await y(l.join(t,a.STORAGE_SERVICE))},tt=async(t,e)=>{if(!e.redux){await y(l.join(t,a.STORE)),await y(l.join(t,a.COUNTER_FEATURE)),await h(l.join(t,a.STORE_PROVIDER));let i=l.join(t,a.PROVIDERS_INDEX),n=await g(i);n=n.replace(/export \* from '\.\/StoreProvider';\n/,""),await u(i,n);let s=[l.join(t,a.ROOT_PAGE),l.join(t,a.LOCALE_PAGE)];for(let r of s)if(x(r)){let o=await g(r);o=o.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),o=o.replace(/<Counter\s*\/>\n?/g,""),await u(r,o)}}},it=async(t,e)=>{if(!e.darkMode){await h(l.join(t,a.THEME_PROVIDER));let i=l.join(t,a.PROVIDERS_INDEX),n=await g(i);n=n.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await u(i,n);let s=l.join(t,a.GLOBALS_CSS);if(x(s)){let r=await g(s);r=r.replace(/@custom-variant dark \(.*?\);\n\n/,""),r=r.replace(/@theme \{[\s\S]*?\}\n/,""),await u(s,r)}if(!e.i18n){let r=l.join(t,a.ROOT_LAYOUT);if(x(r)){let o=await g(r);o=o.replace(/bg-light dark:bg-dark /g,""),await u(r,o)}}}},rt=async(t,e)=>{if(!e.i18n){await y(l.join(t,a.I18N_DIR)),await y(l.join(t,a.LOCALE_DIR)),await h(l.join(t,a.PROXY)),await h(l.join(t,a.MIDDLEWARE)),await h(l.join(t,a.I18N_TYPES)),await h(l.join(t,a.APP_LOCALES));let i=l.join(t,a.TYPES_INDEX);if(x(i)){let o=await g(i);o=o.replace(/export \* from '\.\/i18n';\n/,""),await u(i,o)}let n=l.join(t,a.CONFIG_INDEX);if(x(n)){let o=await g(n);o=o.replace(/export \* from '\.\/app-locales';\n/,""),await u(n,o)}let s=l.join(t,a.NEXT_CONFIG);if(x(s)){let o=await g(s);o=o.replace(/import createNextIntlPlugin from 'next-intl\/plugin';\n/,""),o=o.replace(/const withNextIntl = createNextIntlPlugin\(\);\n/,""),o=o.replace(/export default withNextIntl\(nextConfig\);/,"export default nextConfig;"),await u(s,o)}let r=l.join(t,a.COUNTER_COMPONENT);if(x(r)){let o=await g(r);o=o.replace(/import\s+\{\s*useTranslations\s*\}\s+from\s+['"]next-intl['"];\n/,""),o=o.replace(/\s*const\s+t\s*=\s*useTranslations\(['"]Count['"]\);\n/,""),o=o.replace(/\{t\('currentCount',\s*\{\s*count:\s*value\s*\}\)\}/g,"{value}"),o=o.replace(/\{t\(['"]increment['"]\)\}/g,"Increment"),o=o.replace(/\{t\(['"]decrement['"]\)\}/g,"Decrement"),o=o.replace(/\{t\(['"]reset['"]\)\}/g,"Reset"),await u(r,o)}}},ot=async t=>{await h(l.join(t,a.LICENSE))},nt=async t=>{await h(l.join(t,a.CHANGELOG))},st=async t=>{await h(l.join(t,a.NVM_RC)),await h(l.join(t,a.NPM_RC))};import te from"node:path";var he=async(t,e)=>{let i=[],n=[];e.redux&&(i.push("import { StoreProvider } from '@/providers';"),n.push("StoreProvider")),e.darkMode&&(i.push("import { CustomThemeProvider } from '@/providers';"),n.push("CustomThemeProvider")),e.i18n&&(i.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),i.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
4
- ${i.join(`
2
+ import{Command as gr}from"commander";import ve from"node:path";import B from"picocolors";import $t from"ora";function q(t="",i){let e=$t({text:t,...i});return e.start(),e}import At from"enquirer";var{prompt:jt}=At,$e=async t=>{let i=await jt([{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 ie from"node:fs/promises";import kt from"node:path";import{existsSync as xe}from"node:fs";var y=async t=>ie.readFile(t,"utf-8"),g=async(t,i)=>{await ie.mkdir(kt.dirname(t),{recursive:!0}),await ie.writeFile(t,i,"utf-8")},P=async t=>{xe(t)&&await ie.unlink(t)},w=async t=>{xe(t)&&await ie.rm(t,{recursive:!0,force:!0})},re=async(t,i)=>{let e=await y(t),r=JSON.parse(e),s=i(r);await g(t,JSON.stringify(s,null,2))},C=t=>xe(t);import{exec as Ot}from"node:child_process";import{promisify as _t}from"node:util";var ue=_t(Ot),Ae=async(t,i)=>{try{await ue("git init",{cwd:t}),await ue("git add .",{cwd:t}),await ue('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t}),i&&await ue(`git remote add origin ${i}`,{cwd:t})}catch(e){console.warn("Failed to initialize git repository",e)}};import{exec as Ft}from"node:child_process";import{promisify as Dt}from"node:util";var ye=Dt(Ft),je=async(t,i)=>{let e=`${i} install`;try{await ye(e,{cwd:t})}catch(r){throw new Error(`Failed to install dependencies with ${i}: ${r}`)}},Pe=async(t,i,e)=>{let r=i==="npm"?`${i} run ${e}`:`${i} ${e}`;try{await ye(r,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${e}': ${s}`)}},Lt=()=>{let t=process.env.npm_config_user_agent;if(t){if(t.startsWith("yarn"))return"yarn";if(t.startsWith("pnpm"))return"pnpm";if(t.startsWith("bun"))return"bun"}return"npm"},oe=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":Lt()},ne=async(t,i,e)=>{if(e.length===0)return;let s=`${Mt(i)} ${e.join(" ")}`;try{await ye(s,{cwd:t})}catch(o){throw new Error(`Failed to install packages with ${i}: ${o}`)}},Mt=t=>{switch(t){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}};import L from"picocolors";var Gt={reset:t=>t,red:L.red,green:L.green,yellow:L.yellow,blue:L.blue,cyan:L.cyan,magenta:L.magenta,white:L.white,gray:L.gray,bright:L.bold,dim:L.dim};function H(t,i="reset"){let e=Gt[i]??(r=>r);console.log(e(t))}function A(t){H(`\u2713 ${t}`,"green")}function z(t){H(`\u2716 ${t}`,"red")}var S=z;function D(t){H(`\u2139 ${t}`,"cyan")}function a(t){H(t)}function ke(){console.log(""),H("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),H("\u2551 \u2551","cyan"),H("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),H("\u2551 \u2551","cyan"),H("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}function Oe(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 Ut=t=>t.charAt(0).toUpperCase()+t.slice(1),_=t=>t.replace(/-([a-z])/g,(i,e)=>e.toUpperCase()),V=t=>Ut(_(t));import Ht from"ora";var d=Ht();import zt from"degit";var _e=async t=>{let i=q("Downloading template...");try{await zt("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 Xt from"node:path";var l={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 b={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=q("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 re(Xt.join(t,l.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[b.REDUX_TOOLKIT],delete n.dependencies[b.REACT_REDUX],delete n.dependencies[b.REDUX_PERSIST]),i.httpClient!=="none"||i.reactSecureStorage||delete n.dependencies[b.REACT_SECURE_STORAGE],i.i18n||delete n.dependencies[b.NEXT_INTL],i.darkMode||delete n.dependencies[b.NEXT_THEMES],i.httpClient==="none"?delete n.dependencies[b.AXIOS]:i.httpClient==="fetch"&&delete n.dependencies[b.AXIOS],n)),e.succeed("package.json configured.")}catch(r){throw e.fail("Failed to configure package.json."),r}};import u from"node:path";var De=async(t,i)=>{let e=q("Customizing features...");try{await Wt(t,i),await Yt(t,i),await qt(t,i),await Vt(t,i),await Bt(t,i),await Kt(t),await Jt(t),await Zt(t),e.succeed("Features customized.")}catch(r){throw e.fail("Failed to customize features."),r}},Wt=async(t,i)=>{let e=u.join(t,l.HTTP_UTILS),r=i.httpClient!=="none"||i.reactSecureStorage;if(i.httpClient==="none"){if(await w(u.join(t,l.AXIOS_CLIENT)),await w(u.join(t,l.FETCH_CLIENT)),r)await g(u.join(e,"index.ts"),`export * from './token-store';
3
+ `),await P(u.join(t,l.CLIENT_UTILS));else{await w(e);let o=u.join(t,l.UTILS_INDEX);if(C(o)){let c=await y(o);c=c.replace(/export \* from '\.\/http';\n/,""),await g(o,c)}await P(u.join(t,l.APP_APIS));let n=u.join(t,l.CONFIG_INDEX);if(C(n)){let c=await y(n);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await g(n,c)}}let s=u.join(t,l.CONSTANTS);if(C(s)){let o=await y(s);o=o.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),o=o.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await g(s,o)}if(await w(u.join(t,l.ERRORS_DIR)),!r){await w(u.join(t,l.COMMON_TYPES_DIR)),await w(u.join(t,l.UTILITY_TYPES_DIR));let o=u.join(t,l.TYPES_INDEX);if(C(o)){let n=await y(o);n=n.replace(/export \* from '\.\/utility';\n/,""),n=n.replace(/export \* from '\.\/common';\n/,""),await g(o,n)}}}else if(i.httpClient==="axios"){await w(u.join(t,l.FETCH_CLIENT));let s=await y(u.join(e,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await g(u.join(e,"index.ts"),s);let o=u.join(t,l.HTTP_TYPES);if(C(o)){let n=await y(o);n=n.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await g(o,n)}}else if(i.httpClient==="fetch"){await w(u.join(t,l.AXIOS_CLIENT));let s=await y(u.join(e,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await g(u.join(e,"index.ts"),s);let o=u.join(t,l.HTTP_TYPES);if(C(o)){let n=await y(o);n=n.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await g(o,n)}}},Yt=async(t,i)=>{i.httpClient!=="none"||i.reactSecureStorage||await w(u.join(t,l.STORAGE_SERVICE))},qt=async(t,i)=>{if(!i.redux){await w(u.join(t,l.STORE)),await w(u.join(t,l.COUNTER_FEATURE)),await P(u.join(t,l.STORE_PROVIDER));let e=u.join(t,l.PROVIDERS_INDEX),r=await y(e);r=r.replace(/export \* from '\.\/StoreProvider';\n/,""),await g(e,r);let s=[u.join(t,l.ROOT_PAGE),u.join(t,l.LOCALE_PAGE)];for(let o of s)if(C(o)){let n=await y(o);n=n.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),n=n.replace(/<Counter\s*\/>\n?/g,""),await g(o,n)}}},Vt=async(t,i)=>{if(!i.darkMode){await P(u.join(t,l.THEME_PROVIDER));let e=u.join(t,l.PROVIDERS_INDEX),r=await y(e);r=r.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await g(e,r);let s=u.join(t,l.GLOBALS_CSS);if(C(s)){let o=await y(s);o=o.replace(/@custom-variant dark \(.*?\);\n\n/,""),o=o.replace(/@theme \{[\s\S]*?\}\n/,""),await g(s,o)}if(!i.i18n){let o=u.join(t,l.ROOT_LAYOUT);if(C(o)){let n=await y(o);n=n.replace(/bg-light dark:bg-dark /g,""),await g(o,n)}}}},Bt=async(t,i)=>{if(!i.i18n){await w(u.join(t,l.I18N_DIR)),await w(u.join(t,l.LOCALE_DIR)),await P(u.join(t,l.PROXY)),await P(u.join(t,l.MIDDLEWARE)),await P(u.join(t,l.I18N_TYPES)),await P(u.join(t,l.APP_LOCALES));let e=u.join(t,l.TYPES_INDEX);if(C(e)){let n=await y(e);n=n.replace(/export \* from '\.\/i18n';\n/,""),await g(e,n)}let r=u.join(t,l.CONFIG_INDEX);if(C(r)){let n=await y(r);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await g(r,n)}let s=u.join(t,l.NEXT_CONFIG);if(C(s)){let n=await y(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 g(s,n)}let o=u.join(t,l.COUNTER_COMPONENT);if(C(o)){let n=await y(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 g(o,n)}}},Kt=async t=>{await P(u.join(t,l.LICENSE))},Jt=async t=>{await P(u.join(t,l.CHANGELOG))},Zt=async t=>{await P(u.join(t,l.NVM_RC)),await P(u.join(t,l.NPM_RC))};import Ce from"node:path";var Le=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
+ ${e.join(`
5
5
  `)}
6
6
 
7
7
  export const RootProvider = ({
8
8
  children,
9
- ${e.i18n?`locale,
9
+ ${i.i18n?`locale,
10
10
  messages,`:""}
11
11
  }: {
12
12
  children: React.ReactNode;
13
- ${e.i18n?`locale: SupportedLocale;
13
+ ${i.i18n?`locale: SupportedLocale;
14
14
  messages: AbstractIntlMessages;`:""}
15
15
  }) => {
16
16
  return (
17
- `,r="{children}";e.i18n&&(r=`<NextIntlClientProvider locale={locale} messages={messages}>
18
- ${r}
19
- </NextIntlClientProvider>`),e.darkMode&&(r=`<CustomThemeProvider>
20
- ${r}
21
- </CustomThemeProvider>`),e.redux&&(r=`<StoreProvider>
22
- ${r}
23
- </StoreProvider>`),r==="{children}"&&(r="<>{children}</>"),s+=` ${r}
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 u(te.join(t,a.ROOT_PROVIDER),s)},xe=async(t,e)=>{if(!e.i18n){let i=`import type { Metadata } from 'next';
26
+ `,await g(Ce.join(t,l.ROOT_PROVIDER),s)},Me=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: '${e.projectName}',
40
- description: '${e.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={${e.darkMode?"true":"false"}}>
50
- <body className={\`\${livvic.variable} ${e.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 u(te.join(t,a.ROOT_LAYOUT),i);let n=e.redux?`import { Counter } from '@/features/counter';
58
+ `;await g(Ce.join(t,l.ROOT_LAYOUT),e);let r=i.redux?`import { Counter } from '@/features/counter';
59
59
 
60
- `:"",s=e.redux?`
61
- <Counter />`:"",r=`${n}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 ${e.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 u(te.join(t,a.ROOT_PAGE),r)}};import S from"node:path";import{readdir as Se}from"node:fs/promises";var ye=async(t,e)=>{await at(t,e),await ct(t,e),await pt(t,e),await lt(t,e),await mt(t,e),await dt(t,e),await ut(t,e)},at=async(t,e)=>{e.preCommitHooks||(await y(S.join(t,a.HUSKY_DIR)),await h(S.join(t,a.COMMITLINT_CONFIG)),await h(S.join(t,a.LINTSTAGED_RC)),await z(S.join(t,a.PACKAGE_JSON),i=>(delete i.devDependencies[w.HUSKY],delete i.devDependencies[w.COMMITLINT_CLI],delete i.devDependencies[w.COMMITLINT_CONFIG],delete i.devDependencies[w.LINT_STAGED],delete i.scripts.prepare,delete i.scripts.postinstall,delete i.commitlint,delete i["lint-staged"],i)))},ct=async(t,e)=>{e.commitizen||(await h(S.join(t,a.CZRC)),await z(S.join(t,a.PACKAGE_JSON),i=>(delete i.devDependencies[w.COMMITIZEN],delete i.devDependencies[w.CZ_CONVENTIONAL_CHANGELOG],delete i.config?.commitizen,i.config&&Object.keys(i.config).length===0&&delete i.config,delete i.scripts.commit,i)))},pt=async(t,e)=>{e.ci||await y(S.join(t,a.GITHUB_WORKFLOWS))},lt=async(t,e)=>{let i=S.join(t,a.GITHUB_DIR);if(!e.keepTemplates)await y(S.join(i,a.GITHUB_ISSUE_TEMPLATE)),await h(S.join(i,a.GITHUB_PR_TEMPLATE));else{let n=S.join(i,a.GITHUB_ISSUE_TEMPLATE),s=S.join(i,a.GITHUB_PR_TEMPLATE),r=o=>o.replace(/Teispace/g,e.company).replace(/support@teispace\.com/g,e.email).replace(/Next\.js Starter/g,e.projectName).replace(/\[AUTHOR\]/g,e.author).replace(/\[COMPANY\]/g,e.company).replace(/\[EMAIL\]/g,e.email);if(x(s)){let o=await g(s);o=r(o),await u(s,o)}try{if(x(n)){let o=await Se(n);for(let c of o){let m=S.join(n,c),d=await g(m);d=r(d),await u(m,d)}}}catch{}}},mt=async(t,e)=>{let i=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let n of i)e.communityFiles.includes(n)||await h(S.join(t,n))},dt=async(t,e)=>{if(e.docker){let i=S.join(t,a.ENV_EXAMPLE);if(x(i)){let n=await g(i),s=(r,o)=>{let c=new RegExp(`${r}=.*`);c.test(n)?n=n.replace(c,`${r}=${o}`):n+=`${r}=${o}
70
- `};s("CONTAINER_NAME",e.containerName||"next-app"),s("IMAGE_NAME",e.imageName||"nextjs-starter"),s("IMAGE_TAG",e.imageTag||"latest"),await u(i,n)}}else{await h(S.join(t,a.DOCKERFILE)),await h(S.join(t,a.DOCKER_COMPOSE)),await h(S.join(t,a.DOCKERIGNORE));let i=S.join(t,a.ENV_EXAMPLE);if(x(i)){let n=await g(i);n=n.replace(/# Docker Compose Configuration\n/,""),n=n.replace(/CONTAINER_NAME=.*\n/,""),n=n.replace(/IMAGE_NAME=.*\n/,""),n=n.replace(/IMAGE_TAG=.*\n/,""),await u(i,n)}}},ut=async(t,e)=>{let i=async r=>{let o=await Se(r,{withFileTypes:!0}),c=[];for(let m of o){let d=S.join(r,m.name);m.isDirectory()&&m.name!=="node_modules"&&m.name!==".git"?c.push(...await i(d)):m.isFile()&&m.name.toLowerCase()==="readme.md"&&c.push(d)}return c},n=await i(t),s=S.join(t,a.README);for(let r of n)r!==s&&await h(r);if(e.readme){let r=`# ${e.projectName}
69
+ `;await g(Ce.join(t,l.ROOT_PAGE),o)}};import v from"node:path";import{readdir as Ge}from"node:fs/promises";var Ue=async(t,i)=>{await Qt(t,i),await ei(t,i),await ti(t,i),await ii(t,i),await ri(t,i),await oi(t,i),await ni(t,i)},Qt=async(t,i)=>{i.preCommitHooks||(await w(v.join(t,l.HUSKY_DIR)),await P(v.join(t,l.COMMITLINT_CONFIG)),await P(v.join(t,l.LINTSTAGED_RC)),await re(v.join(t,l.PACKAGE_JSON),e=>(delete e.devDependencies[b.HUSKY],delete e.devDependencies[b.COMMITLINT_CLI],delete e.devDependencies[b.COMMITLINT_CONFIG],delete e.devDependencies[b.LINT_STAGED],delete e.scripts.prepare,delete e.scripts.postinstall,delete e.commitlint,delete e["lint-staged"],e)))},ei=async(t,i)=>{i.commitizen||(await P(v.join(t,l.CZRC)),await re(v.join(t,l.PACKAGE_JSON),e=>(delete e.devDependencies[b.COMMITIZEN],delete e.devDependencies[b.CZ_CONVENTIONAL_CHANGELOG],delete e.config?.commitizen,e.config&&Object.keys(e.config).length===0&&delete e.config,delete e.scripts.commit,e)))},ti=async(t,i)=>{i.ci||await w(v.join(t,l.GITHUB_WORKFLOWS))},ii=async(t,i)=>{let e=v.join(t,l.GITHUB_DIR);if(!i.keepTemplates)await w(v.join(e,l.GITHUB_ISSUE_TEMPLATE)),await P(v.join(e,l.GITHUB_PR_TEMPLATE));else{let r=v.join(e,l.GITHUB_ISSUE_TEMPLATE),s=v.join(e,l.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(C(s)){let n=await y(s);n=o(n),await g(s,n)}try{if(C(r)){let n=await Ge(r);for(let c of n){let p=v.join(r,c),f=await y(p);f=o(f),await g(p,f)}}}catch{}}},ri=async(t,i)=>{let e=[l.CODE_OF_CONDUCT,l.CONTRIBUTING,l.SECURITY];for(let r of e)i.communityFiles.includes(r)||await P(v.join(t,r))},oi=async(t,i)=>{if(i.docker){let e=v.join(t,l.ENV_EXAMPLE);if(C(e)){let r=await y(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 g(e,r)}}else{await P(v.join(t,l.DOCKERFILE)),await P(v.join(t,l.DOCKER_COMPOSE)),await P(v.join(t,l.DOCKERIGNORE));let e=v.join(t,l.ENV_EXAMPLE);if(C(e)){let r=await y(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 g(e,r)}}},ni=async(t,i)=>{let e=async o=>{let n=await Ge(o,{withFileTypes:!0}),c=[];for(let p of n){let f=v.join(o,p.name);p.isDirectory()&&p.name!=="node_modules"&&p.name!==".git"?c.push(...await e(f)):p.isFile()&&p.name.toLowerCase()==="readme.md"&&c.push(f)}return c},r=await e(t),s=v.join(t,l.README);for(let o of r)o!==s&&await P(o);if(i.readme){let o=`# ${i.projectName}
71
71
 
72
- ${e.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
- ${e.packageManager==="npm"?"npm run dev":e.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 u(s,r)}else await h(s)};var Ce=t=>{t.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async e=>{await ft(e)})},ft=async t=>{me(),p("Welcome to the Teispace Next.js App Creator!"),p("");let e=await se(t),i=ie.resolve(process.cwd(),e.projectName);x(i)&&(console.error(L.red(`Error: Directory ${e.projectName} already exists.`)),process.exit(1));let n=D("Initializing project..."),s=async()=>{if(x(i)){n.stop(),console.log(L.yellow(`
84
- Cleaning up: Deleting directory ${e.projectName}...`));try{await y(i),console.log(L.green("Cleanup successful."))}catch(o){console.error(L.red(`Failed to clean up directory ${e.projectName}:`),o)}}},r=async()=>{console.log(L.red(`
85
- Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",r),process.on("SIGTERM",r);try{if(await ue(i),await fe(i,e),await ge(i,e),n.text="Generating code...",await he(i,e),await xe(i,e),n.text="Setting up developer tools...",await ye(i,e),n.text="Initializing Git...",await ae(i),e.gitRemote&&await ce(i,e.gitRemote),n.text="Installing dependencies...",await le(i,e.packageManager),n.text="Formatting and Linting...",await ee(i,e.packageManager,"format"),await ee(i,e.packageManager,"lint:fix"),e.copyEnv){n.text="Creating .env file...";let o=ie.join(i,".env.example"),c=ie.join(i,".env");x(o)&&await(await import("node:fs/promises")).copyFile(o,c)}process.off("SIGINT",r),process.off("SIGTERM",r),n.succeed(L.green(`Project ${e.projectName} created successfully!`)),p(""),p("To get started:"),p(L.cyan(` cd ${e.projectName}`)),p(L.cyan(` ${e.packageManager==="npm"?"npm run dev":e.packageManager+" dev"}`)),p("")}catch(o){n.fail("Failed to create project."),console.error(o),await s(),process.exit(1)}};import v from"picocolors";import ne from"node:path";import gt from"enquirer";var{prompt:ht}=gt,Pe=async(t,e,i,n,s,r,o)=>{let c=[];t||c.push({type:"input",name:"featureName",message:"What is the feature name?",initial:"my-feature",validate:d=>/^[a-z0-9-]+$/.test(d)?!0:"Feature name must be lowercase and contain only alphanumeric characters and hyphens."}),e&&n===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}})),i&&i!=="none"&&r===void 0&&o===void 0&&(c.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),i==="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 ht(c):{};return{featureName:t||m.featureName,hasRedux:e||!1,createStore:n===!0?!1:s!==void 0?!0:m.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:m.persistStore||!1,httpClient:i||"none",createService:r===!0?!1:o!==void 0?!0:m.createService||!1,selectedHttpClient:o||m.selectedHttpClient||(i==="both"?"fetch":i!=="none"?i:void 0)}};import{readFile as xt,access as re}from"node:fs/promises";import Y from"node:path";var H=async t=>{let e=!1,i=!1,n=!1,s=!1;try{let r=Y.join(t,"package.json"),o=await xt(r,"utf-8"),c=JSON.parse(o),m={...c.dependencies,...c.devDependencies};e=!!(m["@reduxjs/toolkit"]&&m["react-redux"]),i=!!m.axios,s=!!m["next-intl"];let d=Y.join(t,"src","lib","utils","http","axios-client");try{await re(d),i=i&&!0}catch{i=!1}let I=Y.join(t,"src","lib","utils","http","fetch-client");try{await re(I),n=!0}catch{n=!1}let C;return i&&n?C="both":i?C="axios":n?C="fetch":C="none",{hasRedux:e,httpClient:C,hasI18n:s}}catch(r){throw new Error(`Failed to detect project setup: ${r}`)}},Ee=async(t,e,i=Y.join("src","features"))=>{let n=Y.join(t,i,e);try{return await re(n),!0}catch{return!1}};import{writeFile as _,mkdir as W}from"node:fs/promises";import N from"node:path";var ve=async t=>{let{featurePath:e}=t;await W(N.join(e,"components"),{recursive:!0}),await W(N.join(e,"hooks"),{recursive:!0}),await W(N.join(e,"types"),{recursive:!0}),t.createStore&&await W(N.join(e,"store"),{recursive:!0}),t.createService&&await W(N.join(e,"services"),{recursive:!0}),await St(t),await yt(t),await Ct(t),await vt(t),t.createStore&&await Pt(t),t.createService&&t.httpClient&&await Et(t)};var St=async t=>{let{featureName:e,featurePath:i}=t,n=G(e),s=`use${n}`,r=`'use client';
83
+ `;await g(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 si(i)})},si=async t=>{ke(),a("Welcome to the Teispace Next.js App Creator!"),a("");let i=await $e(t),e=ve.resolve(process.cwd(),i.projectName);C(e)&&(console.error(B.red(`Error: Directory ${i.projectName} already exists.`)),process.exit(1));let r=q("Initializing project..."),s=async()=>{if(C(e)){r.stop(),console.log(B.yellow(`
84
+ Cleaning up: Deleting directory ${i.projectName}...`));try{await w(e),console.log(B.green("Cleanup successful."))}catch(n){console.error(B.red(`Failed to clean up directory ${i.projectName}:`),n)}}},o=async()=>{console.log(B.red(`
85
+ Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await _e(e),await Fe(e,i),await De(e,i),r.text="Generating code...",await Le(e,i),await Me(e,i),r.text="Setting up developer tools...",await Ue(e,i),r.text="Initializing Git...",await Ae(e,i.gitRemote),r.text="Installing dependencies...",await je(e,i.packageManager),r.text="Formatting and Linting...",await Pe(e,i.packageManager,"format"),await Pe(e,i.packageManager,"lint:fix"),i.copyEnv){r.text="Creating .env file...";let n=ve.join(e,".env.example"),c=ve.join(e,".env");C(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",o),process.off("SIGTERM",o),r.succeed(B.green(`Project ${i.projectName} created successfully!`)),a(""),a("To get started:"),a(B.cyan(` cd ${i.projectName}`)),a(B.cyan(` ${i.packageManager==="npm"?"npm run dev":i.packageManager+" dev"}`)),a("")}catch(n){r.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import I from"picocolors";import Te from"node:path";import ai from"enquirer";var{prompt:ci}=ai,ze=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:f=>/^[a-z0-9-]+$/.test(f)?!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 p=c.length>0?await ci(c):{};return{featureName:t||p.featureName,hasRedux:i||!1,createStore:r===!0?!1:s!==void 0?!0:p.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:p.persistStore||!1,httpClient:e||"none",createService:o===!0?!1:n!==void 0?!0:p.createService||!1,selectedHttpClient:n||p.selectedHttpClient||(e==="both"?"fetch":e!=="none"?e:void 0)}};import{readFile as li,access as we}from"node:fs/promises";import se from"node:path";var X=async t=>{let i=!1,e=!1,r=!1,s=!1;try{let o=se.join(t,"package.json"),n=await li(o,"utf-8"),c=JSON.parse(n),p={...c.dependencies,...c.devDependencies};i=!!(p["@reduxjs/toolkit"]&&p["react-redux"]),e=!!p.axios,s=!!p["next-intl"];let f=se.join(t,"src","lib","utils","http","axios-client");try{await we(f),e=e&&!0}catch{e=!1}let T=se.join(t,"src","lib","utils","http","fetch-client");try{await we(T),r=!0}catch{r=!1}let x;return e&&r?x="both":e?x="axios":r?x="fetch":x="none",{hasRedux:i,httpClient:x,hasI18n:s}}catch(o){throw new Error(`Failed to detect project setup: ${o}`)}},Xe=async(t,i,e=se.join("src","features"))=>{let r=se.join(t,e,i);try{return await we(r),!0}catch{return!1}};import{writeFile as W,mkdir as ae}from"node:fs/promises";import k from"node:path";var We=async t=>{let{featurePath:i}=t;await ae(k.join(i,"components"),{recursive:!0}),await ae(k.join(i,"hooks"),{recursive:!0}),await ae(k.join(i,"types"),{recursive:!0}),t.createStore&&await ae(k.join(i,"store"),{recursive:!0}),t.createService&&await ae(k.join(i,"services"),{recursive:!0}),await pi(t),await mi(t),await di(t),await gi(t),t.createStore&&await ui(t),t.createService&&t.httpClient&&await fi(t)};var pi=async t=>{let{featureName:i,featurePath:e}=t,r=V(i),s=`use${r}`,o=`'use client';
86
86
  import { ${s} } from '../hooks/${s}';
87
87
 
88
- export function ${n}() {
88
+ export function ${r}() {
89
89
  const {} = ${s}();
90
90
 
91
91
  return (
92
92
  <div>
93
- <h2>${n} 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 ${n};
100
- `;await _(N.join(i,"components",`${n}.tsx`),r)},yt=async t=>{let{featureName:e,featurePath:i,createStore:n}=t,s=G(e),r=`use${s}`,o;n?o=`'use client';
99
+ export default ${r};
100
+ `;await W(k.join(e,"components",`${r}.tsx`),o)},mi=async t=>{let{featureName:i,featurePath:e,createStore:r}=t,s=V(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/${e}.selectors';
102
+ import { select${s}State, setLoading, setError } from '../store/${i}.selectors';
103
103
 
104
- export const ${r} = () => {
104
+ export const ${o} = () => {
105
105
  const dispatch = useAppDispatch();
106
106
  const state = useAppSelector(select${s}State);
107
107
 
@@ -121,10 +121,10 @@ export const ${r} = () => {
121
121
  setError: handleSetError,
122
122
  } as const;
123
123
  };
124
- `:o=`'use client';
124
+ `:n=`'use client';
125
125
  import { useState } from 'react';
126
126
 
127
- export const ${r} = () => {
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 ${r} = () => {
133
133
  // Add your methods here
134
134
  } as const;
135
135
  };
136
- `,await _(N.join(i,"hooks",`${r}.ts`),o)},Ct=async t=>{let{featureName:e,featurePath:i,createStore:n}=t,o=`export interface ${`${G(e)}State`} {
136
+ `,await W(k.join(e,"hooks",`${o}.ts`),n)},di=async t=>{let{featureName:i,featurePath:e,createStore:r}=t,n=`export interface ${`${V(i)}State`} {
137
137
  // Add your state properties here
138
- ${n?`loading: boolean;
138
+ ${r?`loading: boolean;
139
139
  error: string | null;`:"// example: value: string;"}
140
140
  }
141
- `;await _(N.join(i,"types",`${e}.types.ts`),o)},Pt=async t=>{let{featureName:e,featurePath:i,persistStore:n}=t,s=G(e),r=O(e),o=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
142
- import { ${s}State } from '../types/${e}.types';
141
+ `;await W(k.join(e,"types",`${i}.types.ts`),n)},ui=async t=>{let{featureName:i,featurePath:e,persistStore:r}=t,s=V(i),o=_(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 ${r}Slice = createSlice({
151
- name: '${r}',
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 ${r}Slice = createSlice({
164
164
  },
165
165
  });
166
166
 
167
- export const { setLoading, setError, resetState } = ${r}Slice.actions;
167
+ export const { setLoading, setError, resetState } = ${o}Slice.actions;
168
168
 
169
- export const ${r}Reducer = ${r}Slice.reducer;
170
- `;await _(N.join(i,"store",`${e}.slice.ts`),o);let c=`import { RootState } from '@/store/rootReducer';
169
+ export const ${o}Reducer = ${o}Slice.reducer;
170
+ `;await W(k.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.${r};
173
- export { setLoading, setError, resetState } from './${e}.slice';
174
- `;if(await _(N.join(i,"store",`${e}.selectors.ts`),c),n){let d=`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 W(k.join(e,"store",`${i}.selectors.ts`),c),r){let f=`import { PersistConfig } from 'redux-persist';
175
175
  import storage from 'redux-persist/lib/storage';
176
- import { ${s}State } from '../types/${e}.types';
176
+ import { ${s}State } from '../types/${i}.types';
177
177
 
178
- export const ${r}PersistConfig: PersistConfig<${s}State> = {
179
- key: '${r}',
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 _(N.join(i,"store","persist.ts"),d)}let m=`export * from './${e}.slice';
184
- export * from './${e}.selectors';${n?`
183
+ `;await W(k.join(e,"store","persist.ts"),f)}let p=`export * from './${i}.slice';
184
+ export * from './${i}.selectors';${r?`
185
185
  export * from './persist';`:""}
186
- `;await _(N.join(i,"store","index.ts"),m)},Et=async t=>{let{featureName:e,featurePath:i,httpClient:n}=t,s=O(e),r;n==="axios"?r=`import { AppApis } from '@/lib/config';
186
+ `;await W(k.join(e,"store","index.ts"),p)},fi=async t=>{let{featureName:i,featurePath:e,httpClient:r}=t,s=_(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
- `:r=`import { AppApis } from '@/lib/config';
195
+ `:o=`import { AppApis } from '@/lib/config';
196
196
  import { fetchClient } from '@/lib/utils/http';
197
197
  import { ResultAsync } from '@/types';
198
198
 
@@ -201,50 +201,50 @@ export const ${s}Service = {
201
201
  return fetchClient.get<string>(AppApis.${s}.getAll);
202
202
  },
203
203
  };
204
- `,await _(N.join(i,"services",`${e}.service.ts`),r)},vt=async t=>{let{featureName:e,featurePath:i,createStore:n,createService:s}=t,r=G(e),o=`export { default as ${r} } from './components/${r}';
205
- export { use${r} } from './hooks/use${r}';
206
- export * from './types/${e}.types';${n?`
204
+ `,await W(k.join(e,"services",`${i}.service.ts`),o)},gi=async t=>{let{featureName:i,featurePath:e,createStore:r,createService:s}=t,o=V(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/${e}.service';`:""}
209
- `;await _(N.join(i,"index.ts"),o)};import{readFile as Te,writeFile as we}from"node:fs/promises";import oe from"node:path";var Re=async(t,e,i,n=oe.join("src","features"))=>{let s=oe.join(t,"src","store","rootReducer.ts");try{let r=await Te(s,"utf-8"),o=O(e),c=`${o}Reducer`,m=i?`${o}PersistConfig`:"",d=n.replace(/^src\//,"@/"),I=i?`import { ${c}, ${m} } from '${d}/${e}/store';`:`import { ${c} } from '${d}/${e}/store';`,C=/import\s+.*\s+from\s+['"].*['"];?\n/g,T=r.match(C);if(T&&T.length>0){let R=T[T.length-1],j=r.lastIndexOf(R);r=r.slice(0,j+R.length)+I+`
210
- `+r.slice(j+R.length)}else r=I+`
211
- `+r;let P=/combineReducers\(\{([^}]*)\}\)/s,b=r.match(P);if(b){let R=b[1],j=i?`
212
- ${o}: persistReducer(${m}, ${c}),`:`
213
- ${o}: ${c},`,Z=R.trimEnd()+j;r=r.replace(P,`combineReducers({${Z}
214
- })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await we(s,r)}catch(r){throw new Error(`Failed to register feature in rootReducer: ${r}`)}},Ie=async(t,e,i,n)=>{let s=oe.join(t,"src","store","rootReducer.ts");try{let r=await Te(s,"utf-8"),o=O(e),c=`${o}Reducer`,m=i?`${o}PersistConfig`:"",d=n.replace(/^src\//,"@/"),I=i?`import { ${c}, ${m} } from '${d}/${e}';`:`import { ${c} } from '${d}/${e}';`,C=/import\s+.*\s+from\s+['"].*['"];?\n/g,T=r.match(C);if(T&&T.length>0){let R=T[T.length-1],j=r.lastIndexOf(R);r=r.slice(0,j+R.length)+I+`
215
- `+r.slice(j+R.length)}else r=I+`
216
- `+r;let P=/combineReducers\(\{([^}]*)\}\)/s,b=r.match(P);if(b){let R=b[1],j=i?`
217
- ${o}: persistReducer(${m}, ${c}),`:`
218
- ${o}: ${c},`,Z=R.trimEnd()+j;r=r.replace(P,`combineReducers({${Z}
219
- })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await we(s,r)}catch(r){throw new Error(`Failed to register slice in rootReducer: ${r}`)}};import{readFile as Tt,writeFile as wt}from"node:fs/promises";import Rt from"node:path";var q=async t=>{let{serviceName:e,projectPath:i}=t,n=O(e),s=Rt.join(i,"src","lib","config","app-apis.ts");try{let r=await Tt(s,"utf-8");if(r.includes(`${n}:`))return;if(!r.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");let c=` ${n}: {
220
- base: \`\${API_PREFIX}/${e}\`,
221
- getAll: \`\${API_PREFIX}/${e}\`,
222
- },`,m=/(\s*)\} as const;/;if(!r.match(m))throw new Error("Could not find closing brace of AppApis object");let I=r.lastIndexOf("} as const;"),C=r.substring(0,I),T=r.substring(I),P=C.trim().endsWith(","),b=C.match(/:\s*\{[^}]*\},\s*$/),R;b||P?R=`${C}
208
+ export * from './services/${i}.service';`:""}
209
+ `;await W(k.join(e,"index.ts"),n)};import{readFile as Ye,writeFile as qe}from"node:fs/promises";import Se from"node:path";var Ve=async(t,i,e,r=Se.join("src","features"))=>{let s=Se.join(t,"src","store","rootReducer.ts");try{let o=await Ye(s,"utf-8"),n=_(i),c=`${n}Reducer`,p=e?`${n}PersistConfig`:"",f=r.replace(/^src\//,"@/"),T=e?`import { ${c}, ${p} } from '${f}/${i}/store';`:`import { ${c} } from '${f}/${i}/store';`,x=/import\s+.*\s+from\s+['"].*['"];?\n/g,N=o.match(x);if(N&&N.length>0){let $=N[N.length-1],U=o.lastIndexOf($);o=o.slice(0,U+$.length)+T+`
210
+ `+o.slice(U+$.length)}else o=T+`
211
+ `+o;let E=/combineReducers\(\{([^}]*)\}\)/s,G=o.match(E);if(G){let $=G[1],U=e?`
212
+ ${n}: persistReducer(${p}, ${c}),`:`
213
+ ${n}: ${c},`,he=$.trimEnd()+U;o=o.replace(E,`combineReducers({${he}
214
+ })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await qe(s,o)}catch(o){throw new Error(`Failed to register feature in rootReducer: ${o}`)}},Be=async(t,i,e,r)=>{let s=Se.join(t,"src","store","rootReducer.ts");try{let o=await Ye(s,"utf-8"),n=_(i),c=`${n}Reducer`,p=e?`${n}PersistConfig`:"",f=r.replace(/^src\//,"@/"),T=e?`import { ${c}, ${p} } from '${f}/${i}';`:`import { ${c} } from '${f}/${i}';`,x=/import\s+.*\s+from\s+['"].*['"];?\n/g,N=o.match(x);if(N&&N.length>0){let $=N[N.length-1],U=o.lastIndexOf($);o=o.slice(0,U+$.length)+T+`
215
+ `+o.slice(U+$.length)}else o=T+`
216
+ `+o;let E=/combineReducers\(\{([^}]*)\}\)/s,G=o.match(E);if(G){let $=G[1],U=e?`
217
+ ${n}: persistReducer(${p}, ${c}),`:`
218
+ ${n}: ${c},`,he=$.trimEnd()+U;o=o.replace(E,`combineReducers({${he}
219
+ })`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await qe(s,o)}catch(o){throw new Error(`Failed to register slice in rootReducer: ${o}`)}};import{readFile as hi,writeFile as xi}from"node:fs/promises";import yi from"node:path";var fe=async t=>{let{serviceName:i,projectPath:e}=t,r=_(i),s=yi.join(e,"src","lib","config","app-apis.ts");try{let o=await hi(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
+ },`,p=/(\s*)\} as const;/;if(!o.match(p))throw new Error("Could not find closing brace of AppApis object");let T=o.lastIndexOf("} as const;"),x=o.substring(0,T),N=o.substring(T),E=x.trim().endsWith(","),G=x.match(/:\s*\{[^}]*\},\s*$/),$;G||E?$=`${x}
223
223
  ${c}
224
- ${T}`:R=C.trimEnd()+`
224
+ ${N}`:$=x.trimEnd()+`
225
225
  `+c+`
226
- `+T,await wt(s,R)}catch(r){throw new Error(`Failed to register API endpoints: ${r}`)}};var Ne=t=>{t.command("feature [name]").description("Generate a new feature module").option("--skip-store","Skip Redux store generation").option("--store <type>","Generate Redux store with persistence option (persist|no-persist)").option("--skip-service","Skip API service generation").option("--service <client>","Generate API service with specific HTTP client (axios|fetch)").option("--path <path>","Custom path for feature generation (default: src/features)").action(async(e,i)=>{try{let n=process.cwd();i.store&&!["persist","no-persist"].includes(i.store)&&(E("Invalid --store option. Use: persist or no-persist"),process.exit(1)),i.service&&!["axios","fetch"].includes(i.service)&&(E("Invalid --service option. Use: axios or fetch"),process.exit(1)),i.skipStore&&i.store&&(E("Cannot use --skip-store and --store together"),process.exit(1)),i.skipService&&i.service&&(E("Cannot use --skip-service and --service together"),process.exit(1)),p(v.cyan(`
226
+ `+N,await xi(s,$)}catch(o){throw new Error(`Failed to register API endpoints: ${o}`)}};var Ke=t=>{t.command("feature [name]").description("Generate a new feature module").option("--skip-store","Skip Redux store generation").option("--store <type>","Generate Redux store with persistence option (persist|no-persist)").option("--skip-service","Skip API service generation").option("--service <client>","Generate API service with specific HTTP client (axios|fetch)").option("--path <path>","Custom path for feature generation (default: src/features)").action(async(i,e)=>{try{let r=process.cwd();e.store&&!["persist","no-persist"].includes(e.store)&&(S("Invalid --store option. Use: persist or no-persist"),process.exit(1)),e.service&&!["axios","fetch"].includes(e.service)&&(S("Invalid --service option. Use: axios or fetch"),process.exit(1)),e.skipStore&&e.store&&(S("Cannot use --skip-store and --store together"),process.exit(1)),e.skipService&&e.service&&(S("Cannot use --skip-service and --service together"),process.exit(1)),a(I.cyan(`
227
227
  \u{1F3AF} Feature Generator
228
- `)),f.start("Detecting project setup...");let s=await H(n);f.succeed("Project setup detected"),p(v.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),p(v.dim(` HTTP Client: ${s.httpClient}`)),p(v.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
229
- `));let r=await Pe(e,s.hasRedux,s.httpClient,i.skipStore,i.store,i.skipService,i.service),o=i.path||ne.join("src","features"),c=ne.join(n,o,r.featureName);await Ee(n,r.featureName,o)&&(E(`Feature '${r.featureName}' already exists at ${o}!`),process.exit(1)),f.start("Generating feature files..."),await ve({featureName:r.featureName,featurePath:c,createStore:r.createStore,persistStore:r.persistStore,createService:r.createService,httpClient:r.selectedHttpClient}),f.succeed("Feature files generated"),r.createService&&(f.start("Registering API endpoints..."),await q({serviceName:r.featureName,projectPath:n}),f.succeed("API endpoints registered")),r.createStore&&s.hasRedux&&(f.start("Registering feature in rootReducer..."),await Re(n,r.featureName,r.persistStore,o),f.succeed("Feature registered in rootReducer"));let d=ne.join(o,r.featureName);p(v.green(`
230
- \u2728 Feature '${r.featureName}' created successfully!
231
- `)),p(v.dim("Generated files:")),p(v.dim(` \u{1F4C2} ${d}/`)),p(v.dim(" \u251C\u2500\u2500 components/")),p(v.dim(" \u251C\u2500\u2500 hooks/")),p(v.dim(" \u251C\u2500\u2500 types/")),r.createStore&&p(v.dim(" \u251C\u2500\u2500 store/")),r.createService&&p(v.dim(" \u251C\u2500\u2500 services/")),p(v.dim(` \u2514\u2500\u2500 index.ts
232
- `)),p(v.cyan("Next steps:"));let I=o.replace(/^src\//,"@/");p(v.dim(` 1. Import and use the feature: import { ${r.featureName} } from '${I}/${r.featureName}'`)),r.createStore&&p(v.dim(` 2. Customize your Redux slice in: ${d}/store/`)),r.createService&&p(v.dim(` 3. Add API methods in: ${d}/services/${r.featureName}.service.ts`)),p("")}catch(n){f.fail("Feature generation failed"),E(`${n}`),process.exit(1)}})};import $ from"picocolors";import k from"node:path";import{existsSync as Dt}from"node:fs";import{mkdir as Gt}from"node:fs/promises";import It from"enquirer";var{prompt:Nt}=It,$e=async(t,e,i)=>{let n=[];t||n.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:r=>/^[a-z0-9-]+$/.test(r)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),e===void 0&&i===void 0&&n.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=n.length>0?await Nt(n):{};return{sliceName:t||s.sliceName,persistSlice:e===!0?!0:i===!1?!1:s.persistSlice||!1}};import{writeFile as K,mkdir as $t}from"node:fs/promises";import V from"node:path";var Oe=async t=>{let{sliceName:e,slicePath:i,persistSlice:n}=t;await $t(i,{recursive:!0});let s=G(e),r=O(e);await Ot(e,i,s),await At(e,i,s,r),await bt(e,i,s,r),n&&await jt(e,i,s,r),await _t(e,i,n)},Ot=async(t,e,i)=>{let n=`export interface ${i}State {
228
+ `)),d.start("Detecting project setup...");let s=await X(r);d.succeed("Project setup detected"),a(I.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),a(I.dim(` HTTP Client: ${s.httpClient}`)),a(I.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
229
+ `));let o=await ze(i,s.hasRedux,s.httpClient,e.skipStore,e.store,e.skipService,e.service),n=e.path||Te.join("src","features"),c=Te.join(r,n,o.featureName);await Xe(r,o.featureName,n)&&(S(`Feature '${o.featureName}' already exists at ${n}!`),process.exit(1)),d.start("Generating feature files..."),await We({featureName:o.featureName,featurePath:c,createStore:o.createStore,persistStore:o.persistStore,createService:o.createService,httpClient:o.selectedHttpClient}),d.succeed("Feature files generated"),o.createService&&(d.start("Registering API endpoints..."),await fe({serviceName:o.featureName,projectPath:r}),d.succeed("API endpoints registered")),o.createStore&&s.hasRedux&&(d.start("Registering feature in rootReducer..."),await Ve(r,o.featureName,o.persistStore,n),d.succeed("Feature registered in rootReducer"));let f=Te.join(n,o.featureName);a(I.green(`
230
+ \u2728 Feature '${o.featureName}' created successfully!
231
+ `)),a(I.dim("Generated files:")),a(I.dim(` \u{1F4C2} ${f}/`)),a(I.dim(" \u251C\u2500\u2500 components/")),a(I.dim(" \u251C\u2500\u2500 hooks/")),a(I.dim(" \u251C\u2500\u2500 types/")),o.createStore&&a(I.dim(" \u251C\u2500\u2500 store/")),o.createService&&a(I.dim(" \u251C\u2500\u2500 services/")),a(I.dim(` \u2514\u2500\u2500 index.ts
232
+ `)),a(I.cyan("Next steps:"));let T=n.replace(/^src\//,"@/");a(I.dim(` 1. Import and use the feature: import { ${o.featureName} } from '${T}/${o.featureName}'`)),o.createStore&&a(I.dim(` 2. Customize your Redux slice in: ${f}/store/`)),o.createService&&a(I.dim(` 3. Add API methods in: ${f}/services/${o.featureName}.service.ts`)),a("")}catch(r){d.fail("Feature generation failed"),S(`${r}`),process.exit(1)}})};import O from"picocolors";import K from"node:path";import{existsSync as Ni}from"node:fs";import{mkdir as bi}from"node:fs/promises";import Pi from"enquirer";var{prompt:Ci}=Pi,Je=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 Ci(r):{};return{sliceName:t||s.sliceName,persistSlice:i===!0?!0:e===!1?!1:s.persistSlice||!1}};import{writeFile as ce,mkdir as vi}from"node:fs/promises";import le from"node:path";var Ze=async t=>{let{sliceName:i,slicePath:e,persistSlice:r}=t;await vi(e,{recursive:!0});let s=V(i),o=_(i);await wi(i,e,s),await Si(i,e,s,o),await Ti(i,e,s,o),r&&await Ei(i,e,s,o),await Ii(i,e,r)},wi=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 K(V.join(e,`${t}.types.ts`),n)},At=async(t,e,i,n)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
238
- import { ${i}State } from './${t}.types';
237
+ `;await ce(le.join(i,`${t}.types.ts`),r)},Si=async(t,i,e,r)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
238
+ import { ${e}State } from './${t}.types';
239
239
 
240
- const initialState: ${i}State = {
240
+ const initialState: ${e}State = {
241
241
  loading: false,
242
242
  error: null,
243
243
  // Add your initial state here
244
244
  };
245
245
 
246
- export const ${n}Slice = createSlice({
247
- name: '${n}',
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 ${n}Slice = createSlice({
260
260
  },
261
261
  });
262
262
 
263
- export const { setLoading, setError, resetState } = ${n}Slice.actions;
263
+ export const { setLoading, setError, resetState } = ${r}Slice.actions;
264
264
 
265
- export const ${n}Reducer = ${n}Slice.reducer;
266
- `;await K(V.join(e,`${t}.slice.ts`),s)},bt=async(t,e,i,n)=>{let s=`import { RootState } from '@/store/rootReducer';
265
+ export const ${r}Reducer = ${r}Slice.reducer;
266
+ `;await ce(le.join(i,`${t}.slice.ts`),s)},Ti=async(t,i,e,r)=>{let s=`import { RootState } from '@/store/rootReducer';
267
267
 
268
- export const select${i}State = (state: RootState) => state.${n};
268
+ export const select${e}State = (state: RootState) => state.${r};
269
269
  export { setLoading, setError, resetState } from './${t}.slice';
270
- `;await K(V.join(e,`${t}.selectors.ts`),s)},jt=async(t,e,i,n)=>{let s=`import { PersistConfig } from 'redux-persist';
270
+ `;await ce(le.join(i,`${t}.selectors.ts`),s)},Ei=async(t,i,e,r)=>{let s=`import { PersistConfig } from 'redux-persist';
271
271
  import storage from 'redux-persist/lib/storage';
272
- import { ${i}State } from './${t}.types';
272
+ import { ${e}State } from './${t}.types';
273
273
 
274
- export const ${n}PersistConfig: PersistConfig<${i}State> = {
275
- key: '${n}',
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 K(V.join(e,"persist.ts"),s)},_t=async(t,e,i)=>{let n=`export * from './${t}.slice';
279
+ `;await ce(le.join(i,"persist.ts"),s)},Ii=async(t,i,e)=>{let r=`export * from './${t}.slice';
280
280
  export * from './${t}.selectors';
281
- export * from './${t}.types';${i?`
281
+ export * from './${t}.types';${e?`
282
282
  export * from './persist';`:""}
283
- `;await K(V.join(e,"index.ts"),n)};import{access as Ft}from"node:fs/promises";import Ae from"node:path";var be=async(t,e,i=Ae.join("src","store","slices"))=>{let n=Ae.join(t,i,e);try{return await Ft(n),!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(e,i)=>{try{let n=process.cwd();i.persist&&i.noPersist===!0&&(E("Cannot use --persist and --no-persist together"),process.exit(1)),p($.cyan(`
283
+ `;await ce(le.join(i,"index.ts"),r)};import{access as Ri}from"node:fs/promises";import Qe from"node:path";var et=async(t,i,e=Qe.join("src","store","slices"))=>{let r=Qe.join(t,e,i);try{return await Ri(r),!0}catch{return!1}};var tt=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&&(S("Cannot use --persist and --no-persist together"),process.exit(1)),a(O.cyan(`
284
284
  \u{1F527} Slice Generator
285
- `)),f.start("Detecting project setup...");let s=await H(n);f.succeed("Project setup detected"),s.hasRedux||(f.fail("Redux is not setup in this project"),E("Please install @reduxjs/toolkit and react-redux first"),p($.dim(`
285
+ `)),d.start("Detecting project setup...");let s=await X(r);d.succeed("Project setup detected"),s.hasRedux||(d.fail("Redux is not setup in this project"),S("Please install @reduxjs/toolkit and react-redux first"),a(O.dim(`
286
286
  Run: npm install @reduxjs/toolkit react-redux
287
- `)),process.exit(1)),p($.dim(` Redux: \u2713
288
- `));let r=await $e(e,i.persist,i.noPersist===!0?!1:void 0),o,c,m;if(i.path){let P=i.path.replace(/^src\//,"");P.startsWith("features/")?(c=P.split("/")[1],o=k.join("src","features",c,"store"),m=k.join(n,o,r.sliceName)):(o=k.join("src",P),c=P.split("/")[0],m=k.join(n,o,r.sliceName))}else c=r.sliceName,o=k.join("src","features",c,"store"),m=k.join(n,o,r.sliceName);let d=k.join(n,o);Dt(d)||await Gt(d,{recursive:!0}),await be(n,r.sliceName,o)&&(E(`Slice '${r.sliceName}' already exists at ${o}!`),process.exit(1)),f.start("Generating slice files..."),await Oe({sliceName:r.sliceName,slicePath:m,persistSlice:r.persistSlice}),f.succeed("Slice files generated"),f.start("Registering slice in rootReducer..."),await Ie(n,r.sliceName,r.persistSlice,o),f.succeed("Slice registered in rootReducer");let C=k.join(o,r.sliceName);p($.green(`
289
- \u2728 Slice '${r.sliceName}' created successfully!
290
- `)),p($.dim("Generated files:")),p($.dim(` \u{1F4C2} ${C}/`)),p($.dim(` \u251C\u2500\u2500 ${r.sliceName}.slice.ts`)),p($.dim(` \u251C\u2500\u2500 ${r.sliceName}.selectors.ts`)),r.persistSlice&&p($.dim(" \u251C\u2500\u2500 persist.ts")),p($.dim(` \u251C\u2500\u2500 ${r.sliceName}.types.ts`)),p($.dim(` \u2514\u2500\u2500 index.ts
291
- `)),p($.cyan("Next steps:"));let T=o.replace(/^src\//,"@/");p($.dim(` 1. Import actions: import { setLoading, setError } from '${T}/${r.sliceName}'`)),p($.dim(" 2. Use in component: dispatch(setLoading(true))")),p("")}catch(n){f.fail("Slice generation failed"),E(`${n}`),process.exit(1)}})};import F from"picocolors";import U from"node:path";import{existsSync as Xt}from"node:fs";import{mkdir as zt}from"node:fs/promises";import _e from"enquirer";var Fe=async(t,e,i,n)=>{let s=t||(await _e.prompt({type:"input",name:"serviceName",message:"Service name (kebab-case):",validate:o=>o?/^[a-z0-9-]+$/.test(o)?!0:"Service name must be lowercase with hyphens only":"Service name is required"})).serviceName,r;return e!==void 0?r="axios":i!==void 0?r="fetch":n==="axios"?r="axios":n==="fetch"?r="fetch":n==="both"?r=(await _e.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:r="axios",{serviceName:s,httpClient:r}};import{writeFile as Lt}from"node:fs/promises";import kt from"node:path";var De=async t=>{await Mt(t)},Mt=async t=>{let{serviceName:e,servicePath:i,httpClient:n}=t,s=O(e),r;n==="axios"?r=`import { AppApis } from '@/lib/config';
287
+ `)),process.exit(1)),a(O.dim(` Redux: \u2713
288
+ `));let o=await Je(i,e.persist,e.noPersist===!0?!1:void 0),n,c,p;if(e.path){let E=e.path.replace(/^src\//,"");E.startsWith("features/")?(c=E.split("/")[1],n=K.join("src","features",c,"store"),p=K.join(r,n,o.sliceName)):(n=K.join("src",E),c=E.split("/")[0],p=K.join(r,n,o.sliceName))}else c=o.sliceName,n=K.join("src","features",c,"store"),p=K.join(r,n,o.sliceName);let f=K.join(r,n);Ni(f)||await bi(f,{recursive:!0}),await et(r,o.sliceName,n)&&(S(`Slice '${o.sliceName}' already exists at ${n}!`),process.exit(1)),d.start("Generating slice files..."),await Ze({sliceName:o.sliceName,slicePath:p,persistSlice:o.persistSlice}),d.succeed("Slice files generated"),d.start("Registering slice in rootReducer..."),await Be(r,o.sliceName,o.persistSlice,n),d.succeed("Slice registered in rootReducer");let x=K.join(n,o.sliceName);a(O.green(`
289
+ \u2728 Slice '${o.sliceName}' created successfully!
290
+ `)),a(O.dim("Generated files:")),a(O.dim(` \u{1F4C2} ${x}/`)),a(O.dim(` \u251C\u2500\u2500 ${o.sliceName}.slice.ts`)),a(O.dim(` \u251C\u2500\u2500 ${o.sliceName}.selectors.ts`)),o.persistSlice&&a(O.dim(" \u251C\u2500\u2500 persist.ts")),a(O.dim(` \u251C\u2500\u2500 ${o.sliceName}.types.ts`)),a(O.dim(` \u2514\u2500\u2500 index.ts
291
+ `)),a(O.cyan("Next steps:"));let N=n.replace(/^src\//,"@/");a(O.dim(` 1. Import actions: import { setLoading, setError } from '${N}/${o.sliceName}'`)),a(O.dim(" 2. Use in component: dispatch(setLoading(true))")),a("")}catch(r){d.fail("Slice generation failed"),S(`${r}`),process.exit(1)}})};import Y from"picocolors";import Q from"node:path";import{existsSync as _i}from"node:fs";import{mkdir as Fi}from"node:fs/promises";import it from"enquirer";var rt=async(t,i,e,r)=>{let s=t||(await it.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 it.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:o="axios",{serviceName:s,httpClient:o}};import{writeFile as $i}from"node:fs/promises";import Ai from"node:path";var ot=async t=>{await ji(t)},ji=async t=>{let{serviceName:i,servicePath:e,httpClient:r}=t,s=_(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
- `:r=`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,13 +306,93 @@ export const ${s}Service = {
306
306
  return fetchClient.get<string>(AppApis.${s}.getAll);
307
307
  },
308
308
  };
309
- `;let o=`${e}.service.ts`;await Lt(kt.join(i,o),r)};import{existsSync as Ut}from"node:fs";import Ht from"node:path";var Ge=async(t,e,i)=>{let n=Ht.join(t,i,`${e}.service.ts`);return Ut(n)};var Le=t=>{t.command("service [name]").description("Generate an API service").option("--path <path>","Custom path for service generation (default: create new feature)").option("--axios","Use Axios HTTP client").option("--fetch","Use Fetch HTTP client").action(async(e,i)=>{try{let n=process.cwd();i.axios&&i.fetch&&(E("Cannot use --axios and --fetch together"),process.exit(1)),p(F.cyan(`
309
+ `;let n=`${i}.service.ts`;await $i(Ai.join(e,n),o)};import{existsSync as ki}from"node:fs";import Oi from"node:path";var nt=async(t,i,e)=>{let r=Oi.join(t,e,`${i}.service.ts`);return ki(r)};var st=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&&(S("Cannot use --axios and --fetch together"),process.exit(1)),a(Y.cyan(`
310
310
  \u{1F527} Service Generator
311
- `)),f.start("Detecting project setup...");let s=await H(n);f.succeed("Project setup detected"),s.httpClient==="none"&&(f.fail("No HTTP client is setup in this project"),E("Please setup either AxiosClient or FetchClient first"),p(F.dim(`
311
+ `)),d.start("Detecting project setup...");let s=await X(r);d.succeed("Project setup detected"),s.httpClient==="none"&&(d.fail("No HTTP client is setup in this project"),S("Please setup either AxiosClient or FetchClient first"),a(Y.dim(`
312
312
  Check: lib/utils/http/axios-client or lib/utils/http/fetch-client
313
- `)),process.exit(1));let r=[];(s.httpClient==="axios"||s.httpClient==="both")&&r.push("Axios \u2713"),(s.httpClient==="fetch"||s.httpClient==="both")&&r.push("Fetch \u2713"),p(F.dim(` HTTP Clients: ${r.join(", ")}
314
- `));let o=await Fe(e,i.axios,i.fetch,s.httpClient),c,m,d;if(i.path){let P=i.path.replace(/^src\//,"");P.startsWith("features/")?(m=P.split("/")[1],c=U.join("src","features",m,"services"),d=U.join(n,c)):(c=U.join("src",P),m=P.split("/")[0],d=U.join(n,c))}else m=o.serviceName,c=U.join("src","features",m,"services"),d=U.join(n,c);Xt(d)||await zt(d,{recursive:!0}),await Ge(n,o.serviceName,c)&&(E(`Service '${o.serviceName}' already exists at ${c}!`),process.exit(1)),f.start("Generating service files..."),await De({serviceName:o.serviceName,servicePath:d,httpClient:o.httpClient}),f.succeed("Service files generated"),f.start("Registering API endpoints..."),await q({serviceName:o.serviceName,projectPath:n}),f.succeed("API endpoints registered");let C=U.join(c,`${o.serviceName}.service.ts`);p(F.green(`
315
- \u2728 Service '${o.serviceName}' created successfully!
316
- `)),p(F.dim("Generated files:")),p(F.dim(` \u{1F4C4} ${C}
317
- `)),p(F.cyan("Next steps:"));let T=c.replace(/^src\//,"@/");p(F.dim(` 1. Import service: import { ${o.serviceName}Service } from '${T}/${o.serviceName}.service'`)),p(F.dim(` 2. Use in component: const data = await ${o.serviceName}Service.getAll()`)),p("")}catch(n){f.fail("Service generation failed"),E(`${n}`),process.exit(1)}})};var ke=t=>{Ce(t),Ne(t),je(t),Le(t)};async function Wt(){de({logger:e=>J(e)});let t=new Yt;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),ke(t),t.parse()}Wt().catch(t=>{let e=t&&typeof t=="object"&&"message"in t?t.message:String(t);J(`Unexpected error: ${e}`)});
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"),a(Y.dim(` HTTP Clients: ${o.join(", ")}
314
+ `));let n=await rt(i,e.axios,e.fetch,s.httpClient),c,p,f;if(e.path){let E=e.path.replace(/^src\//,"");E.startsWith("features/")?(p=E.split("/")[1],c=Q.join("src","features",p,"services"),f=Q.join(r,c)):(c=Q.join("src",E),p=E.split("/")[0],f=Q.join(r,c))}else p=n.serviceName,c=Q.join("src","features",p,"services"),f=Q.join(r,c);_i(f)||await Fi(f,{recursive:!0}),await nt(r,n.serviceName,c)&&(S(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),d.start("Generating service files..."),await ot({serviceName:n.serviceName,servicePath:f,httpClient:n.httpClient}),d.succeed("Service files generated"),d.start("Registering API endpoints..."),await fe({serviceName:n.serviceName,projectPath:r}),d.succeed("API endpoints registered");let x=Q.join(c,`${n.serviceName}.service.ts`);a(Y.green(`
315
+ \u2728 Service '${n.serviceName}' created successfully!
316
+ `)),a(Y.dim("Generated files:")),a(Y.dim(` \u{1F4C4} ${x}
317
+ `)),a(Y.cyan("Next steps:"));let N=c.replace(/^src\//,"@/");a(Y.dim(` 1. Import service: import { ${n.serviceName}Service } from '${N}/${n.serviceName}.service'`)),a(Y.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),a("")}catch(r){d.fail("Service generation failed"),S(`${r}`),process.exit(1)}})};import m from"picocolors";import dr from"enquirer";import{mkdir as Ie,readdir as Di,readFile as Re,writeFile as Ne,access as Li}from"node:fs/promises";import j from"node:path";import{fileURLToPath as Mi}from"node:url";var ct=()=>{let t=Mi(import.meta.url),i=j.dirname(t);return j.resolve(i,"..","..","..","..","..","Templates","nextjs-starter")},at=async(t,i)=>{let e=j.join(t,"src","lib","utils","http",`${i}-client`);try{return await Li(e),!0}catch{return!1}},Ee=async(t,i)=>{await Ie(i,{recursive:!0});let e=await Di(t,{withFileTypes:!0});for(let r of e){let s=j.join(t,r.name),o=j.join(i,r.name);if(r.isDirectory())await Ee(s,o);else{let n=await Re(s,"utf-8");await Ne(o,n)}}},Gi=async(t,i)=>{let e=j.join(t,"src","lib","utils","http","index.ts");await Ie(j.dirname(e),{recursive:!0});let r="";try{r=await Re(e,"utf-8")}catch{}let s=[],o=new Set;if(r){let n=r.matchAll(/export \{ .+ \} from '\.\/(.+)';/g);for(let c of n)o.add(c[1])}((i==="axios"||i==="both")&&!o.has("axios-client")||o.has("axios-client"))&&(s.push("export { axiosClient } from './axios-client';"),s.push("export { createAxiosClient } from './axios-client';")),((i==="fetch"||i==="both")&&!o.has("fetch-client")||o.has("fetch-client"))&&(s.push("export { fetchClient } from './fetch-client';"),s.push("export { createFetchClient } from './fetch-client';")),r.includes("export * from './token-store'"),s.push("export * from './token-store';"),await Ne(e,s.join(`
318
+ `)+`
319
+ `)},Ui=async t=>{let i=ct(),e=j.join(i,"src","lib","utils","http"),r=j.join(t,"src","lib","utils","http");await Ie(r,{recursive:!0});let s=["client-utils.ts","token-store.ts"];for(let o of s){let n=j.join(e,o),c=j.join(r,o);try{let p=await Re(n,"utf-8");await Ne(c,p)}catch{console.warn(`Warning: Could not copy ${o}`)}}},lt=async t=>{let{projectPath:i,clientType:e}=t,r=ct(),s=[];if(await Ui(i),(e==="axios"||e==="both")&&!await at(i,"axios")){let n=j.join(r,"src","lib","utils","http","axios-client"),c=j.join(i,"src","lib","utils","http","axios-client");await Ee(n,c),s.push("axios")}if((e==="fetch"||e==="both")&&!await at(i,"fetch")){let n=j.join(r,"src","lib","utils","http","fetch-client"),c=j.join(i,"src","lib","utils","http","fetch-client");await Ee(n,c),s.push("fetch")}return await Gi(i,e),s},pt=t=>{let i=[];return(t==="axios"||t==="both")&&i.push("axios"),i};import{readFile as pe,writeFile as ee,access as Hi}from"node:fs/promises";import M from"node:path";import{fileURLToPath as zi}from"node:url";var Xi=()=>{let t=zi(import.meta.url),i=M.dirname(t);return M.resolve(i,"..","..","..","..","..","Templates","nextjs-starter")},mt=async t=>{let i=M.join(t,"src","providers","CustomThemeProvider.tsx");try{return await Hi(i),!0}catch{return!1}},dt=async t=>{if(await mt(t))return!1;let e=Xi(),r=M.join(e,"src","providers","CustomThemeProvider.tsx"),s=M.join(t,"src","providers","CustomThemeProvider.tsx"),o=await pe(r,"utf-8");return await ee(s,o),await qi(t),await Vi(t),await Wi(t),await Yi(t),!0},Wi=async t=>{let i=M.join(t,"src","providers","index.ts");try{let e=await pe(i,"utf-8");if(e.includes("CustomThemeProvider"))return;e+=`
320
+ export { CustomThemeProvider } from './CustomThemeProvider';
321
+ `,await ee(i,e)}catch{await ee(i,`export { CustomThemeProvider } from './CustomThemeProvider';
322
+ export { RootProvider } from './RootProvider';
323
+ export { StoreProvider } from './StoreProvider';
324
+ `)}},Yi=async t=>{let i=M.join(t,"src","providers","RootProvider.tsx");try{let e=await pe(i,"utf-8");if(e.includes("CustomThemeProvider"))return;if(e.includes("import { StoreProvider } from '@/providers';"))e=e.replace("import { StoreProvider } from '@/providers';","import { CustomThemeProvider, StoreProvider } from '@/providers';");else if(e.includes("import {"))e=e.replace(/import \{([^}]+)\} from '@\/providers';/,"import { CustomThemeProvider, $1 } from '@/providers';");else{let r=e.indexOf("import");if(r!==-1){let s=e.indexOf(`
325
+ `,r);e=e.slice(0,s+1)+`import { CustomThemeProvider } from '@/providers';
326
+ `+e.slice(s+1)}}e.includes("<StoreProvider>")?(e=e.replace(/(<StoreProvider>)/,`$1
327
+ <CustomThemeProvider>`),e=e.replace(/(<\/StoreProvider>)/,` </CustomThemeProvider>
328
+ $1`)):(e=e.replace(/(return\s*\(\s*<[^>]+>)/,`$1
329
+ <CustomThemeProvider>`),e=e.replace(/(<\/[^>]+>\s*\);)/,` </CustomThemeProvider>
330
+ $1`)),await ee(i,e)}catch(e){throw new Error(`Failed to update RootProvider: ${e}`)}},ut=async t=>await mt(t),qi=async t=>{let i=M.join(t,"src","styles","globals.css");try{let e=await pe(i,"utf-8");if(e.includes("@custom-variant dark")&&e.includes("--color-dark")&&e.includes("--color-light"))return;e.includes("@custom-variant dark")||(e.includes("@import 'tailwindcss';")?e=e.replace("@import 'tailwindcss';",`@import 'tailwindcss';
331
+
332
+ @custom-variant dark (&:where(.dark, .dark *));`):e=`@custom-variant dark (&:where(.dark, .dark *));
333
+
334
+ `+e),e.includes("@theme")?e.includes("--color-dark")||(e=e.replace(/(@theme\s*{[^}]*)(})/,`$1 --color-dark: #202938;
335
+ --color-light: #f5f5f5;
336
+ $2`)):e+=`
337
+ @theme {
338
+ --color-dark: #202938;
339
+ --color-light: #f5f5f5;
340
+ }
341
+ `,await ee(i,e)}catch{}},Vi=async t=>{let i=[M.join(t,"src","app","layout.tsx"),M.join(t,"src","app","[locale]","layout.tsx")];for(let e of i)try{let r=await pe(e,"utf-8");if(r.includes("dark:bg-dark"))continue;r=r.replace(/<body([^>]*?)className={`([^`]*)`}([^>]*)>/,(s,o,n,c)=>{let p=n;return p.includes("bg-light")||(p=p.trim()+" bg-light dark:bg-dark"),`<body${o}className={\`${p}\`}${c}>`}),r=r.replace(/<body([^>]*?)className="([^"]*)"([^>]*)>/,(s,o,n,c)=>{let p=n;return p.includes("bg-light")||(p=p.trim()+" bg-light dark:bg-dark"),`<body${o}className="${p}"${c}>`}),await ee(e,r)}catch{}},ft=()=>["next-themes"];import{readFile as ge,writeFile as me,mkdir as gt,access as ht}from"node:fs/promises";import F from"node:path";import{fileURLToPath as Bi}from"node:url";var Ki=()=>{let t=Bi(import.meta.url),i=F.dirname(t);return F.resolve(i,"..","..","..","..","..","Templates","nextjs-starter")},xt=async t=>{let i=F.join(t,"src","store"),e=F.join(t,"src","providers","StoreProvider.tsx");try{return await ht(i),await ht(e),!0}catch{return!1}},yt=async t=>{if(await xt(t))return!1;let e=Ki(),r=F.join(t,"src","store");return await gt(r,{recursive:!0}),await gt(F.join(r,"slices"),{recursive:!0}),await Ji(e,t),await Zi(e,t),await Qi(t),await er(t),!0},Ji=async(t,i)=>{let e=["index.ts","hooks.ts","persistor.ts","rootReducer.ts"];for(let r of e){let s=F.join(t,"src","store",r),o=F.join(i,"src","store",r),n=await ge(s,"utf-8");await me(o,n)}},Zi=async(t,i)=>{let e=F.join(t,"src","providers","StoreProvider.tsx"),r=F.join(i,"src","providers","StoreProvider.tsx"),s=await ge(e,"utf-8");await me(r,s)},Qi=async t=>{let i=F.join(t,"src","providers","index.ts");try{let e=await ge(i,"utf-8");if(e.includes("StoreProvider"))return;e+=`
342
+ export { StoreProvider } from './StoreProvider';
343
+ `,await me(i,e)}catch{await me(i,`export { StoreProvider } from './StoreProvider';
344
+ export { RootProvider } from './RootProvider';
345
+ `)}},er=async t=>{let i=F.join(t,"src","providers","RootProvider.tsx");try{let e=await ge(i,"utf-8");if(e.includes("StoreProvider"))return;if(e.includes("from '@/providers'"))e=e.replace(/import \{ ([^}]+) \} from '@\/providers';/,"import { StoreProvider, $1 } from '@/providers';");else{let s=e.indexOf("'use client';");if(s!==-1){let o=e.indexOf(`
346
+ `,s);e=e.slice(0,o+1)+`import { StoreProvider } from '@/providers';
347
+ `+e.slice(o+1)}}let r=e.match(/(return\s*\(\s*)/);if(r){let o=e.indexOf(r[0])+r[0].length,n=1,c=o;for(let x=o;x<e.length;x++)if(e[x]==="("&&n++,e[x]===")"&&(n--,n===0)){c=x;break}let p=e.slice(0,o),f=e.slice(o,c),T=e.slice(c);e=`${p}
348
+ <StoreProvider>
349
+ ${f}
350
+ </StoreProvider>
351
+ ${T}`}await me(i,e)}catch(e){throw new Error(`Failed to update RootProvider: ${e}`)}},Pt=async t=>await xt(t),Ct=()=>["@reduxjs/toolkit","react-redux","redux-persist"];import{readFile as Z,writeFile as J,mkdir as de,readdir as tr}from"node:fs/promises";import*as R from"fs";import h from"node:path";import{fileURLToPath as ir}from"url";var rr=ir(import.meta.url),or=h.dirname(rr),nr=()=>h.resolve(or,"..","..","..","..","..","Templates","nextjs-starter"),vt=async(t,i)=>{await de(i,{recursive:!0});let e=await tr(t,{withFileTypes:!0});for(let r of e){let s=h.join(t,r.name),o=h.join(i,r.name);if(r.isDirectory())await vt(s,o);else{let n=await Z(s,"utf-8");await J(o,n)}}},te=async(t,i)=>{await de(h.dirname(i),{recursive:!0});let e=await Z(t,"utf-8");await J(i,e)},be=t=>{let i=h.join(t,"src","i18n");return R.existsSync(i)},wt=async t=>{try{if(be(t)){D("next-intl is already configured in your project."),D("Skipping i18n setup...");return}let i=nr(),e=h.join(i,"src","i18n"),r=h.join(t,"src","i18n");R.existsSync(e)&&(await vt(e,r),A("Copied i18n directory"));let s=h.join(i,"src","types","i18n.ts"),o=h.join(t,"src","types","i18n.ts");R.existsSync(s)&&(await te(s,o),A("Copied types/i18n.ts"));let n=h.join(i,"src","lib","config","app-locales.ts"),c=h.join(t,"src","lib","config","app-locales.ts");R.existsSync(n)&&(await te(n,c),A("Copied lib/config/app-locales.ts")),await sr(t),await ar(t),await cr(t,i),await lr(t),await pr(t),await mr(t,i)}catch(i){throw z(`Failed to setup i18n: ${i}`),i}},sr=async t=>{let i=h.join(t,"src","lib","config","index.ts");try{let e=await Z(i,"utf-8");if(e.includes("export * from './app-locales'")){D("appLocales already exported in lib/config/index.ts");return}let r=e+`export * from './app-locales';
352
+ `;await J(i,r),A("Updated lib/config/index.ts to export appLocales")}catch{await de(h.dirname(i),{recursive:!0}),await J(i,`export * from './app-locales';
353
+ `),A("Created lib/config/index.ts with appLocales export")}},ar=async t=>{let i=h.join(t,"src","types","index.ts");try{let e=await Z(i,"utf-8");if(e.includes("export * from './i18n'")){D("i18n types already exported in types/index.ts");return}let r=e+`export * from './i18n';
354
+ `;await J(i,r),A("Updated types/index.ts to export i18n types")}catch{await de(h.dirname(i),{recursive:!0}),await J(i,`export * from './i18n';
355
+ `),A("Created types/index.ts with i18n types export")}},cr=async(t,i)=>{let e=h.join(t,"src","proxy.ts"),r=h.join(t,"src","middleware.ts");try{if((await Z(r,"utf-8")).includes("next-intl")){D("Middleware already configured with next-intl");return}}catch{}let s=h.join(i,"src","proxy.ts");R.existsSync(s)&&(await te(s,e),A("Created src/proxy.ts with next-intl middleware"))},lr=async t=>{let i=h.join(t,"next.config.ts");try{let e=await Z(i,"utf-8");if(e.includes("createNextIntlPlugin")||e.includes("next-intl")){D("next.config.ts already configured with next-intl");return}let r=`import createNextIntlPlugin from 'next-intl/plugin';
356
+ `,s=`const withNextIntl = createNextIntlPlugin();
357
+ `,o=e.match(/export default (.+);/);if(!o){z("Could not find export default in next.config.ts");return}let n=o[1].trim(),c=e,p=e.match(/import .+ from .+;\n/g);if(p){let f=p[p.length-1],T=e.lastIndexOf(f);c=e.slice(0,T+f.length)+`
358
+ `+r+e.slice(T+f.length)}else c=r+`
359
+ `+e;c=c.replace(/export default/,s+`
360
+ export default`),c=c.replace(`export default ${n};`,`export default withNextIntl(${n});`),await J(i,c),A("Updated next.config.ts to use createNextIntlPlugin")}catch{z("next.config.ts not found")}},pr=async t=>{let i=h.join(t,"src","providers","RootProvider.tsx");try{let e=await Z(i,"utf-8");if(e.includes("NextIntlClientProvider")||e.includes("next-intl")){D("RootProvider already configured with NextIntlClientProvider");return}let r=`import { SupportedLocale } from '@/types/i18n';
361
+ import { NextIntlClientProvider } from 'next-intl';
362
+ import { AbstractIntlMessages } from 'next-intl';
363
+ `,s=e,o=e.match(/import .+ from .+;\n/g);if(o){let n=o[o.length-1],c=e.lastIndexOf(n);s=e.slice(0,c+n.length)+r+e.slice(c+n.length)}if(s=s.replace(/export const RootProvider = \(\{\s*children,?\s*\}: \{[^}]+\}\)/,`export const RootProvider = ({
364
+ children,
365
+ locale,
366
+ messages,
367
+ }: {
368
+ children: React.ReactNode;
369
+ locale: SupportedLocale;
370
+ messages: AbstractIntlMessages;
371
+ })`),s.includes("return <>{children}</>;"))s=s.replace("return <>{children}</>;",`return (
372
+ <NextIntlClientProvider locale={locale} messages={messages}>
373
+ {children}
374
+ </NextIntlClientProvider>
375
+ );`);else{let n=s.match(/return \(([\s\S]+?)\);[\s]*\}/);if(n){let c=n[1];if(c.match(/>\s*\{children\}\s*</)){let f=c.replace(/>\s*\{children\}\s*</,`>
376
+ <NextIntlClientProvider locale={locale} messages={messages}>
377
+ {children}
378
+ </NextIntlClientProvider>
379
+ <`);s=s.replace(c,f)}}}await J(i,s),A("Updated RootProvider to include NextIntlClientProvider")}catch{z("RootProvider.tsx not found")}},mr=async(t,i)=>{let e=h.join(t,"src","app","[locale]","layout.tsx"),r=h.join(t,"src","app","[locale]");if(!R.existsSync(r)){await de(r,{recursive:!0});let s=h.join(i,"src","app","[locale]","layout.tsx");R.existsSync(s)&&(await te(s,e),A("Created [locale]/layout.tsx with i18n configuration"));let o=h.join(t,"src","app","page.tsx"),n=h.join(t,"src","app","[locale]","page.tsx");if(R.existsSync(o))R.renameSync(o,n),A("Moved page.tsx to [locale]/page.tsx");else{let p=h.join(i,"src","app","[locale]","page.tsx");R.existsSync(p)&&(await te(p,n),A("Created [locale]/page.tsx from template"))}let c=h.join(t,"src","app","layout.tsx");R.existsSync(c)&&(R.unlinkSync(c),D("Removed old app/layout.tsx"));return}if(!R.existsSync(e)){let s=h.join(i,"src","app","[locale]","layout.tsx");R.existsSync(s)&&(await te(s,e),A("Created [locale]/layout.tsx with i18n configuration"));return}try{let s=await Z(e,"utf-8");if(s.includes("next-intl")||s.includes("setRequestLocale")){D("[locale]/layout.tsx already configured with i18n");return}D("[locale]/layout.tsx exists but may need manual i18n configuration")}catch{}};var{prompt:It}=dr,Rt=t=>{t.command("setup").description("Setup additional features for your Next.js project").option("--http-client <type>","Setup HTTP client (axios|fetch|both)").option("--dark-theme","Setup dark theme support").option("--redux","Setup Redux Toolkit with persistence").option("--i18n","Setup next-intl for internationalization").action(async i=>{try{let e=process.cwd();if(a(m.cyan(`
380
+ \u{1F527} Setup Wizard
381
+ `)),!i.httpClient&&!i.darkTheme&&!i.redux&&!i.i18n){let r=await It([{type:"select",name:"feature",message:"What would you like to setup?",choices:["HTTP Client (Axios/Fetch)","Dark Theme","Redux Toolkit","Internationalization (next-intl)","Cancel"]}]);if(r.feature==="Cancel"){a(m.yellow("Setup cancelled."));return}r.feature==="HTTP Client (Axios/Fetch)"?await ur(e):r.feature==="Dark Theme"?await St(e):r.feature==="Redux Toolkit"?await Tt(e):r.feature==="Internationalization (next-intl)"&&await Et(e)}else i.httpClient&&await fr(e,i.httpClient),i.darkTheme&&await St(e),i.redux&&await Tt(e),i.i18n&&await Et(e)}catch(e){d.fail("Setup failed"),S(`${e}`),process.exit(1)}})},ur=async t=>{d.start("Detecting project setup...");let i=await X(t);if(d.succeed("Project setup detected"),a(m.dim(`
382
+ Current HTTP Client: ${i.httpClient}
383
+ `)),i.httpClient==="both"){a(m.green("\u2713 Both Axios and Fetch clients are already setup!"));return}let e=[],r={};i.httpClient==="none"?(e.push("Axios Client","Fetch Client","Both (Axios + Fetch)"),r["Axios Client"]="axios",r["Fetch Client"]="fetch",r["Both (Axios + Fetch)"]="both"):i.httpClient==="axios"?(e.push("Add Fetch Client","Reinstall Axios Client"),r["Add Fetch Client"]="fetch",r["Reinstall Axios Client"]="axios"):i.httpClient==="fetch"&&(e.push("Add Axios Client","Reinstall Fetch Client"),r["Add Axios Client"]="axios",r["Reinstall Fetch Client"]="fetch");let{clientChoice:s}=await It([{type:"select",name:"clientChoice",message:"Which HTTP client would you like to setup?",choices:e}]),o=r[s];await Nt(t,o)},fr=async(t,i)=>{["axios","fetch","both"].includes(i)||(S(`Invalid HTTP client type: ${i}`),a(m.dim("Valid options: axios, fetch, both")),process.exit(1)),d.start("Detecting project setup...");let e=await X(t);d.succeed("Project setup detected");let r=i;if(r==="both"&&e.httpClient==="both"){a(m.green(`
384
+ \u2713 Both Axios and Fetch clients are already setup!`));return}if(r==="axios"&&(e.httpClient==="axios"||e.httpClient==="both")){a(m.green(`
385
+ \u2713 Axios client is already setup!`));return}if(r==="fetch"&&(e.httpClient==="fetch"||e.httpClient==="both")){a(m.green(`
386
+ \u2713 Fetch client is already setup!`));return}await Nt(t,r)},Nt=async(t,i)=>{d.start("Setting up HTTP client files...");let e=await lt({projectPath:t,clientType:i});d.succeed("HTTP client files setup complete");let r=pt(i);if(r.length>0){d.start("Installing required packages...");let s=await oe(t);await ne(t,s,r),d.succeed("Packages installed")}a(m.green(`
387
+ \u2728 HTTP Client setup completed successfully!
388
+ `)),e.length>0&&(a(m.dim("Installed clients:")),e.forEach(s=>{a(m.dim(` \u2713 ${s}`))}),a("")),a(m.cyan("Next steps:")),a(m.dim(" 1. HTTP client is now available at: src/lib/utils/http/")),(i==="axios"||e.includes("axios"))&&a(m.dim(" 2. Use Axios: import { axiosClient } from '@/lib/utils/http';")),(i==="fetch"||e.includes("fetch"))&&a(m.dim(" 2. Use Fetch: import { fetchClient } from '@/lib/utils/http';")),a(m.dim(" 3. Create services using: npm run make service <name>")),a("")},St=async t=>{d.start("Checking dark theme setup...");let i=await ut(t);if(d.succeed("Check complete"),i){a(m.green(`
389
+ \u2713 Dark theme is already setup!`));return}d.start("Setting up dark theme...");let e=await dt(t);if(d.succeed("Dark theme files setup complete"),e){let r=ft();d.start("Installing required packages...");let s=await oe(t);await ne(t,s,r),d.succeed("Packages installed")}a(m.green(`
390
+ \u2728 Dark theme setup completed successfully!
391
+ `)),a(m.dim("What was added:")),a(m.dim(" \u2713 CustomThemeProvider component")),a(m.dim(" \u2713 Integrated with RootProvider")),a(m.dim(" \u2713 next-themes package installed")),a(""),a(m.cyan("Next steps:")),a(m.dim(" 1. Dark theme is now available in your app")),a(m.dim(" 2. Users can toggle between light/dark/system modes")),a(m.dim(" 3. Use the theme: import { useTheme } from 'next-themes';")),a(m.dim(" 4. Add dark mode classes to your Tailwind CSS (e.g., dark:bg-gray-900)")),a("")},Tt=async t=>{d.start("Checking Redux setup...");let i=await Pt(t);if(d.succeed("Check complete"),i){a(m.green(`
392
+ \u2713 Redux Toolkit is already setup!`));return}d.start("Setting up Redux Toolkit...");let e=await yt(t);if(d.succeed("Redux Toolkit files setup complete"),e){let r=Ct();d.start("Installing required packages...");let s=await oe(t);await ne(t,s,r),d.succeed("Packages installed")}a(m.green(`
393
+ \u2728 Redux Toolkit setup completed successfully!
394
+ `)),a(m.dim("What was added:")),a(m.dim(" \u2713 Store configuration (src/store)")),a(m.dim(" \u2713 Redux hooks (useAppDispatch, useAppSelector)")),a(m.dim(" \u2713 Redux Persist integration")),a(m.dim(" \u2713 StoreProvider component")),a(m.dim(" \u2713 Integrated with RootProvider")),a(m.dim(" \u2713 Required packages installed")),a(""),a(m.cyan("Next steps:")),a(m.dim(" 1. Redux store is now available in your app")),a(m.dim(" 2. Use hooks: import { useAppDispatch, useAppSelector } from '@/store/hooks';")),a(m.dim(" 3. Create features with state: npm run make feature <name> --store persist")),a(m.dim(" 4. Create slices: npm run make slice <name>")),a("")},Et=async t=>{d.start("Checking i18n setup...");let i=be(t);if(d.succeed("Check complete"),i){a(m.green(`
395
+ \u2713 next-intl is already setup!`));return}d.start("Setting up next-intl (i18n)..."),await wt(t),d.succeed("next-intl setup complete");let e=["next-intl"];d.start("Installing required packages...");let r=await oe(t);await ne(t,r,e),d.succeed("Packages installed"),a(m.green(`
396
+ \u2728 next-intl (i18n) setup completed successfully!
397
+ `)),a(m.dim("What was added:")),a(m.dim(" \u2713 i18n configuration (src/i18n)")),a(m.dim(" \u2713 Translation files (src/i18n/translations)")),a(m.dim(" \u2713 Locale types and config")),a(m.dim(" \u2713 Middleware for routing (src/proxy.ts)")),a(m.dim(" \u2713 Updated next.config.ts")),a(m.dim(" \u2713 Updated RootProvider with NextIntlClientProvider")),a(m.dim(" \u2713 Created [locale] route structure")),a(m.dim(" \u2713 next-intl package installed")),a(""),a(m.cyan("Next steps:")),a(m.dim(" 1. Add more locales in src/lib/config/app-locales.ts")),a(m.dim(" 2. Add translations in src/i18n/translations/<locale>.json")),a(m.dim(" 3. Use translations: import { useTranslations } from 'next-intl';")),a(m.dim(" 4. Use navigation: import { Link, useRouter } from '@/i18n/navigation';")),a(m.dim(" 5. Update SupportedLocale type in src/types/i18n.ts")),a("")};var bt=t=>{He(t),Rt(t),Ke(t),tt(t),st(t)};async function hr(){Oe({logger:i=>z(i)});let t=new gr;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),bt(t),t.parse()}hr().catch(t=>{let i=t&&typeof t=="object"&&"message"in t?t.message:String(t);z(`Unexpected error: ${i}`)});
318
398
  //# sourceMappingURL=index.js.map