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