@teispace/next-maker 1.3.0 → 1.5.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 +137 -121
- package/dist/index.js.map +4 -4
- package/dist/src/commands/setup.d.ts.map +1 -1
- package/dist/src/config/paths.d.ts +2 -0
- package/dist/src/config/paths.d.ts.map +1 -1
- package/dist/src/services/setup/dark-theme/injectors.d.ts.map +1 -1
- package/dist/src/services/setup/http-client/assets.d.ts +4 -0
- package/dist/src/services/setup/http-client/assets.d.ts.map +1 -0
- package/dist/src/services/setup/http-client/checks.d.ts +8 -0
- package/dist/src/services/setup/http-client/checks.d.ts.map +1 -0
- package/dist/src/services/setup/http-client/index.d.ts +2 -0
- package/dist/src/services/setup/http-client/index.d.ts.map +1 -0
- package/dist/src/services/setup/http-client/injectors.d.ts +10 -0
- package/dist/src/services/setup/http-client/injectors.d.ts.map +1 -0
- package/dist/src/services/setup/i18n/injectors.d.ts.map +1 -1
- package/dist/src/services/setup/redux/injectors.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as qr}from"commander";import ge from"node:path";import U from"picocolors";import At from"ora";function N(t="",r){let e=At({text:t,...r});return e.start(),e}import bt from"enquirer";var{prompt:_t}=bt,we=async t=>{let r=await _t([{type:"input",name:"projectName",message:"What is the project name?",initial:t||"my-app",skip:!!t,validate:e=>/^[a-z0-9-_]+$/.test(e)?!0:"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:e=>/^\d+\.\d+\.\d+$/.test(e)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:e=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)?!0:"Please enter a valid email address."},{type:"select",name:"packageManager",message:"Which package manager would you like to use?",choices:["npm","yarn","pnpm","bun"],initial:1},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",validate:e=>{if(!e)return!0;let i=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!i.test(e)&&!s.test(e)?"Please enter a valid GitHub repository URL (e.g., https://github.com/user/repo)":!0}},{type:"confirm",name:"keepTemplates",message:"Do you want to keep GitHub issue and pull request templates?",initial:!1},{type:"select",name:"httpClient",message:"Which HTTP client do you want to use?",choices:["axios","fetch","both","none"],initial:1},{type:"confirm",name:"reactSecureStorage",message:"Do you want to include react-secure-storage?",initial:!0,skip:function(){let e=this.state?.answers??this.enquirer?.answers??{};return!!(e.httpClient&&e.httpClient!=="none")}},{type:"confirm",name:"darkMode",message:"Do you want to include Dark Mode (Tailwind + next-themes)?",initial:!0},{type:"confirm",name:"redux",message:"Do you want to include Redux Toolkit?",initial:!0},{type:"confirm",name:"i18n",message:"Do you want to include Internationalization (next-intl)?",initial:!0},{type:"multiselect",name:"communityFiles",message:"Select community files to include:",choices:[{name:"CODE_OF_CONDUCT.md",value:"CODE_OF_CONDUCT.md"},{name:"CONTRIBUTING.md",value:"CONTRIBUTING.md"},{name:"SECURITY.md",value:"SECURITY.md"}],initial:[]},{type:"confirm",name:"readme",message:"Do you want to create a README.md?",initial:!0},{type:"confirm",name:"docker",message:"Do you want to include Docker configuration?",initial:!1},{type:"input",name:"containerName",message:"Docker Container Name:",initial:"next-app",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:e=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(e)?!0:"Invalid Docker container name."},{type:"input",name:"imageName",message:"Docker Image Name:",initial:"nextjs-starter",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:e=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(e)?!0:"Invalid Docker image name (must be lowercase)."},{type:"input",name:"imageTag",message:"Docker Image Tag:",initial:"latest",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:e=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(e)?!0:"Invalid Docker image tag."},{type:"confirm",name:"ci",message:"Do you want to include GitHub Actions (CI/CD)?",initial:!1},{type:"confirm",name:"preCommitHooks",message:"Do you want to setup pre-commit hooks (Husky, Commitlint, Lint-staged)?",initial:!0},{type:"confirm",name:"commitizen",message:"Do you want to setup Commitizen?",initial:!0},{type:"confirm",name:"copyEnv",message:"Want to copy .env.example to .env?",initial:!0}]);if(r.company=r.author,r.gitRemote&&!r.gitHomepage){let e=r.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");r.gitHomepage=`${e}#readme`,r.gitIssues=`${e}/issues`}return r};import J from"node:fs/promises";import Te from"node:path";import{existsSync as de}from"node:fs";var d=async t=>J.readFile(t,"utf-8"),u=async(t,r)=>{await J.mkdir(Te.dirname(t),{recursive:!0}),await J.writeFile(t,r,"utf-8")},M=async(t,r)=>{await J.mkdir(Te.dirname(r),{recursive:!0}),await J.copyFile(t,r)},h=async t=>{de(t)&&await J.unlink(t)},P=async t=>{de(t)&&await J.rm(t,{recursive:!0,force:!0})},Z=async(t,r)=>{let e=await d(t),i=JSON.parse(e),s=r(i);await u(t,JSON.stringify(s,null,2))},m=t=>de(t);import{exec as jt}from"node:child_process";import{promisify as kt}from"node:util";var ie=kt(jt),Ee=async(t,r)=>{try{await ie("git init",{cwd:t}),await ie("git add .",{cwd:t}),await ie('git commit -m "Initial commit from @teispace/next-maker"',{cwd:t}),r&&await ie(`git remote add origin ${r}`,{cwd:t})}catch(e){console.warn("Failed to initialize git repository",e)}};import{exec as Ft}from"node:child_process";import{promisify as Dt}from"node:util";var ue=Dt(Ft),Re=async(t,r)=>{let e=`${r} install`;try{await ue(e,{cwd:t})}catch(i){throw new Error(`Failed to install dependencies with ${r}: ${i}`)}},k=async(t,r,e)=>{let i=r==="npm"?`${r} run ${e}`:`${r} ${e}`;try{await ue(i,{cwd:t})}catch(s){console.warn(`Warning: Failed to run script '${e}': ${s}`)}},Lt=()=>{let t=process.env.npm_config_user_agent;if(t){if(t.startsWith("yarn"))return"yarn";if(t.startsWith("pnpm"))return"pnpm";if(t.startsWith("bun"))return"bun"}return"npm"},Y=async t=>{let{existsSync:r}=await import("node:fs"),e=await import("node:path");return r(e.join(t,"pnpm-lock.yaml"))?"pnpm":r(e.join(t,"yarn.lock"))?"yarn":r(e.join(t,"bun.lockb"))?"bun":r(e.join(t,"package-lock.json"))?"npm":Lt()},Gt=async(t,r,e)=>{if(e.length===0)return;let s=`${Mt(r)} ${e.join(" ")}`;try{await ue(s,{cwd:t})}catch(o){throw new Error(`Failed to install packages with ${r}: ${o}`)}},Mt=t=>{switch(t){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}},F=async(t,r)=>{let e=await Y(t);await Gt(t,e,[r])};import b from"picocolors";var Ht={reset:t=>t,red:b.red,green:b.green,yellow:b.yellow,blue:b.blue,cyan:b.cyan,magenta:b.magenta,white:b.white,gray:b.gray,bright:b.bold,dim:b.dim};function V(t,r="reset"){let e=Ht[r]??(i=>i);console.log(e(t))}function ne(t){V(`\u2716 ${t}`,"red")}var C=ne;function l(t){V(t)}function Ie(){console.log(""),V("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),V("\u2551 \u2551","cyan"),V("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),V("\u2551 \u2551","cyan"),V("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}function Ne(t){let{logger:r=n=>console.error(n),exitOnCancel:e=process.env.NODE_ENV!=="test"}=t??{},i=()=>{console.log(""),console.log(""),r("Setup cancelled by user"),console.log(""),e&&process.exit(0)},s=n=>{if(n!==null&&typeof n=="object"&&"code"in n&&n.code==="ERR_USE_AFTER_CLOSE"){i();return}if(n instanceof Error){r(`Uncaught exception: ${n.message}`);return}r(`Uncaught exception: ${String(n)}`)},o=n=>{if(n instanceof Error){r(`Unhandled promise rejection: ${n.message}`);return}r(`Unhandled promise rejection: ${String(n)}`)};return process.on("SIGINT",i),process.on("SIGTERM",i),process.on("uncaughtException",s),process.on("unhandledRejection",o),()=>{process.off("SIGINT",i),process.off("SIGTERM",i),process.off("uncaughtException",s),process.off("unhandledRejection",o)}}var Ut=t=>t.charAt(0).toUpperCase()+t.slice(1),A=t=>t.replace(/-([a-z])/g,(r,e)=>e.toUpperCase()),H=t=>Ut(A(t));import Xt from"ora";var x=Xt();import zt from"degit";var Oe=async t=>{let r=N("Downloading template...");try{await zt("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(t),r.succeed("Template downloaded successfully.")}catch(e){throw r.fail("Failed to download template."),e}};import Jt from"node:path";var a={NEXT_CONFIG:"next.config.ts",TAILWIND_CONFIG:"tailwind.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",ESLINT_CONFIG:"eslint.config.mjs",TS_CONFIG:"tsconfig.json",PACKAGE_JSON:"package.json",ENV_EXAMPLE:".env.example",GITIGNORE:".gitignore",README:"README.md",LICENSE:"LICENSE",CHANGELOG:"CHANGELOG.md",NVM_RC:".nvmrc",NPM_RC:".npmrc",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md"};var R={REDUX_TOOLKIT:"@reduxjs/toolkit",REACT_REDUX:"react-redux",REDUX_PERSIST:"redux-persist",REACT_SECURE_STORAGE:"react-secure-storage",NEXT_INTL:"next-intl",NEXT_THEMES:"next-themes",AXIOS:"axios",HUSKY:"husky",COMMITLINT_CLI:"@commitlint/cli",COMMITLINT_CONFIG:"@commitlint/config-conventional",LINT_STAGED:"lint-staged",COMMITIZEN:"commitizen",CZ_CONVENTIONAL_CHANGELOG:"cz-conventional-changelog"};var $e=async(t,r)=>{let e=N("Configuring package.json...");try{let i=r.gitRemote,s=r.gitHomepage,o=r.gitIssues;r.gitRemote&&(r.gitRemote.startsWith("git@github.com:")&&(i=r.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"")),s||(s=`${i.replace(/\.git$/,"")}#readme`),o||(o=`${i.replace(/\.git$/,"")}/issues`),i.endsWith(".git")||(i=`${i}.git`)),await Z(Jt.join(t,a.PACKAGE_JSON),n=>(n.name=r.projectName,n.version=r.version,n.description=r.description,n.author=r.author,delete n.packageManager,r.gitRemote?(s&&(n.homepage=s),o&&(n.bugs={url:o}),i&&(n.repository={type:"git",url:i})):(delete n.homepage,delete n.bugs,delete n.repository),r.redux||(delete n.dependencies[R.REDUX_TOOLKIT],delete n.dependencies[R.REACT_REDUX],delete n.dependencies[R.REDUX_PERSIST]),r.httpClient!=="none"||r.reactSecureStorage||delete n.dependencies[R.REACT_SECURE_STORAGE],r.i18n||delete n.dependencies[R.NEXT_INTL],r.darkMode||delete n.dependencies[R.NEXT_THEMES],r.httpClient==="none"?delete n.dependencies[R.AXIOS]:r.httpClient==="fetch"&&delete n.dependencies[R.AXIOS],n)),e.succeed("package.json configured.")}catch(i){throw e.fail("Failed to configure package.json."),i}};import f from"node:path";var Ae=async(t,r)=>{let e=N("Customizing features...");try{await Yt(t,r),await Vt(t,r),await Wt(t,r),await Bt(t,r),await Kt(t,r),await qt(t),await Zt(t),await Qt(t),e.succeed("Features customized.")}catch(i){throw e.fail("Failed to customize features."),i}},Yt=async(t,r)=>{let e=f.join(t,a.HTTP_UTILS),i=r.httpClient!=="none"||r.reactSecureStorage;if(r.httpClient==="none"){if(await P(f.join(t,a.AXIOS_CLIENT)),await P(f.join(t,a.FETCH_CLIENT)),i)await u(f.join(e,"index.ts"),`export * from './token-store';
|
|
3
|
-
`),await
|
|
4
|
-
${
|
|
2
|
+
var Kt=Object.defineProperty;var qt=(e,i)=>()=>(e&&(i=e(e=0)),i);var Zt=(e,i)=>{for(var t in i)Kt(e,t,{get:i[t],enumerable:!0})};var Me={};Zt(Me,{PROJECT_PATHS:()=>a});var a,I=qt(()=>{"use strict";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",AXIOS_CLIENT_FILE:"src/lib/utils/http/axios-client/index.ts",FETCH_CLIENT_FILE:"src/lib/utils/http/fetch-client/index.ts",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"}});import{Command as No}from"commander";import ve from"node:path";import Y from"picocolors";import Qt from"ora";function O(e="",i){let t=Qt({text:e,...i});return t.start(),t}import ei from"enquirer";var{prompt:ti}=ei,be=async e=>{let i=await ti([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:t=>/^[a-z0-9-_]+$/.test(t)?!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:t=>/^\d+\.\d+\.\d+$/.test(t)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:t=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?!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:t=>{if(!t)return!0;let r=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!r.test(t)&&!s.test(t)?"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 t=this.state?.answers??this.enquirer?.answers??{};return!!(t.httpClient&&t.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:t=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(t)?!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:t=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(t)?!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:t=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(t)?!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 t=i.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");i.gitHomepage=`${t}#readme`,i.gitIssues=`${t}/issues`}return i};import V from"node:fs/promises";import _e from"node:path";import{existsSync as ye}from"node:fs";var d=async e=>V.readFile(e,"utf-8"),u=async(e,i)=>{await V.mkdir(_e.dirname(e),{recursive:!0}),await V.writeFile(e,i,"utf-8")},$=async(e,i)=>{await V.mkdir(_e.dirname(i),{recursive:!0}),await V.copyFile(e,i)},v=async e=>{ye(e)&&await V.unlink(e)},h=async e=>{ye(e)&&await V.rm(e,{recursive:!0,force:!0})},te=async(e,i)=>{let t=await d(e),r=JSON.parse(t),s=i(r);await u(e,JSON.stringify(s,null,2))},l=e=>ye(e);import{exec as ii}from"node:child_process";import{promisify as oi}from"node:util";var le=oi(ii),je=async(e,i)=>{try{await le("git init",{cwd:e}),await le("git add .",{cwd:e}),await le('git commit -m "Initial commit from @teispace/next-maker"',{cwd:e}),i&&await le(`git remote add origin ${i}`,{cwd:e})}catch(t){console.warn("Failed to initialize git repository",t)}};import{exec as ri}from"node:child_process";import{promisify as ni}from"node:util";var Pe=ni(ri),Fe=async(e,i)=>{let t=`${i} install`;try{await Pe(t,{cwd:e})}catch(r){throw new Error(`Failed to install dependencies with ${i}: ${r}`)}},L=async(e,i,t)=>{let r=i==="npm"?`${i} run ${t}`:`${i} ${t}`;try{await Pe(r,{cwd:e})}catch(s){console.warn(`Warning: Failed to run script '${t}': ${s}`)}},si=()=>{let e=process.env.npm_config_user_agent;if(e){if(e.startsWith("yarn"))return"yarn";if(e.startsWith("pnpm"))return"pnpm";if(e.startsWith("bun"))return"bun"}return"npm"},G=async e=>{let{existsSync:i}=await import("node:fs"),t=await import("node:path");return i(t.join(e,"pnpm-lock.yaml"))?"pnpm":i(t.join(e,"yarn.lock"))?"yarn":i(t.join(e,"bun.lockb"))?"bun":i(t.join(e,"package-lock.json"))?"npm":si()},ai=async(e,i,t)=>{if(t.length===0)return;let s=`${ci(i)} ${t.join(" ")}`;try{await Pe(s,{cwd:e})}catch(o){throw new Error(`Failed to install packages with ${i}: ${o}`)}},ci=e=>{switch(e){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}},D=async(e,i)=>{let t=await G(e);await ai(e,t,[i])};import M from"picocolors";var li={reset:e=>e,red:M.red,green:M.green,yellow:M.yellow,blue:M.blue,cyan:M.cyan,magenta:M.magenta,white:M.white,gray:M.gray,bright:M.bold,dim:M.dim};function B(e,i="reset"){let t=li[i]??(r=>r);console.log(t(e))}function pe(e){B(`\u2716 ${e}`,"red")}var E=pe;function m(e){B(e)}function ke(){console.log(""),B("\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"),B("\u2551 \u2551","cyan"),B("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),B("\u2551 \u2551","cyan"),B("\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(e){let{logger:i=n=>console.error(n),exitOnCancel:t=process.env.NODE_ENV!=="test"}=e??{},r=()=>{console.log(""),console.log(""),i("Setup cancelled by user"),console.log(""),t&&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 pi=e=>e.charAt(0).toUpperCase()+e.slice(1),j=e=>e.replace(/-([a-z])/g,(i,t)=>t.toUpperCase()),J=e=>pi(j(e));import mi from"ora";var y=mi();import di from"degit";var Le=async e=>{let i=O("Downloading template...");try{await di("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(e),i.succeed("Template downloaded successfully.")}catch(t){throw i.fail("Failed to download template."),t}};import ui from"node:path";I();var A={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 Ge=async(e,i)=>{let t=O("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 te(ui.join(e,a.PACKAGE_JSON),n=>(n.name=i.projectName,n.version=i.version,n.description=i.description,n.author=i.author,delete n.packageManager,i.gitRemote?(s&&(n.homepage=s),o&&(n.bugs={url:o}),r&&(n.repository={type:"git",url:r})):(delete n.homepage,delete n.bugs,delete n.repository),i.redux||(delete n.dependencies[A.REDUX_TOOLKIT],delete n.dependencies[A.REACT_REDUX],delete n.dependencies[A.REDUX_PERSIST]),i.httpClient!=="none"||i.reactSecureStorage||delete n.dependencies[A.REACT_SECURE_STORAGE],i.i18n||delete n.dependencies[A.NEXT_INTL],i.darkMode||delete n.dependencies[A.NEXT_THEMES],i.httpClient==="none"?delete n.dependencies[A.AXIOS]:i.httpClient==="fetch"&&delete n.dependencies[A.AXIOS],n)),t.succeed("package.json configured.")}catch(r){throw t.fail("Failed to configure package.json."),r}};import f from"node:path";I();var He=async(e,i)=>{let t=O("Customizing features...");try{await fi(e,i),await gi(e,i),await xi(e,i),await hi(e,i),await yi(e,i),await Pi(e),await Si(e),await vi(e),t.succeed("Features customized.")}catch(r){throw t.fail("Failed to customize features."),r}},fi=async(e,i)=>{let t=f.join(e,a.HTTP_UTILS),r=i.httpClient!=="none"||i.reactSecureStorage;if(i.httpClient==="none"){if(await h(f.join(e,a.AXIOS_CLIENT)),await h(f.join(e,a.FETCH_CLIENT)),r)await u(f.join(t,"index.ts"),`export * from './token-store';
|
|
3
|
+
`),await v(f.join(e,a.CLIENT_UTILS));else{await h(t);let o=f.join(e,a.UTILS_INDEX);if(l(o)){let c=await d(o);c=c.replace(/export \* from '\.\/http';\n/,""),await u(o,c)}await v(f.join(e,a.APP_APIS));let n=f.join(e,a.CONFIG_INDEX);if(l(n)){let c=await d(n);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await u(n,c)}}let s=f.join(e,a.CONSTANTS);if(l(s)){let o=await d(s);o=o.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),o=o.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await u(s,o)}if(await h(f.join(e,a.ERRORS_DIR)),!r){await h(f.join(e,a.COMMON_TYPES_DIR)),await h(f.join(e,a.UTILITY_TYPES_DIR));let o=f.join(e,a.TYPES_INDEX);if(l(o)){let n=await d(o);n=n.replace(/export \* from '\.\/utility';\n/,""),n=n.replace(/export \* from '\.\/common';\n/,""),await u(o,n)}}}else if(i.httpClient==="axios"){await h(f.join(e,a.FETCH_CLIENT));let s=await d(f.join(t,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await u(f.join(t,"index.ts"),s);let o=f.join(e,a.HTTP_TYPES);if(l(o)){let n=await d(o);n=n.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await u(o,n)}}else if(i.httpClient==="fetch"){await h(f.join(e,a.AXIOS_CLIENT));let s=await d(f.join(t,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await u(f.join(t,"index.ts"),s);let o=f.join(e,a.HTTP_TYPES);if(l(o)){let n=await d(o);n=n.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),n=n.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await u(o,n)}}},gi=async(e,i)=>{i.httpClient!=="none"||i.reactSecureStorage||await h(f.join(e,a.STORAGE_SERVICE))},xi=async(e,i)=>{if(!i.redux){await h(f.join(e,a.STORE)),await h(f.join(e,a.COUNTER_FEATURE)),await v(f.join(e,a.STORE_PROVIDER));let t=f.join(e,a.PROVIDERS_INDEX),r=await d(t);r=r.replace(/export \* from '\.\/StoreProvider';\n/,""),await u(t,r);let s=[f.join(e,a.ROOT_PAGE),f.join(e,a.LOCALE_PAGE)];for(let o of s)if(l(o)){let n=await d(o);n=n.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),n=n.replace(/<Counter\s*\/>\n?/g,""),await u(o,n)}}},hi=async(e,i)=>{if(!i.darkMode){await v(f.join(e,a.THEME_PROVIDER));let t=f.join(e,a.PROVIDERS_INDEX),r=await d(t);r=r.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await u(t,r);let s=f.join(e,a.GLOBALS_CSS);if(l(s)){let o=await d(s);o=o.replace(/@custom-variant dark \(.*?\);\n\n/,""),o=o.replace(/@theme \{[\s\S]*?\}\n/,""),await u(s,o)}if(!i.i18n){let o=f.join(e,a.ROOT_LAYOUT);if(l(o)){let n=await d(o);n=n.replace(/bg-light dark:bg-dark /g,""),await u(o,n)}}}},yi=async(e,i)=>{if(!i.i18n){await h(f.join(e,a.I18N_DIR)),await h(f.join(e,a.LOCALE_DIR)),await v(f.join(e,a.PROXY)),await v(f.join(e,a.MIDDLEWARE)),await v(f.join(e,a.I18N_TYPES)),await v(f.join(e,a.APP_LOCALES));let t=f.join(e,a.TYPES_INDEX);if(l(t)){let n=await d(t);n=n.replace(/export \* from '\.\/i18n';\n/,""),await u(t,n)}let r=f.join(e,a.CONFIG_INDEX);if(l(r)){let n=await d(r);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await u(r,n)}let s=f.join(e,a.NEXT_CONFIG);if(l(s)){let n=await d(s);n=n.replace(/import createNextIntlPlugin from 'next-intl\/plugin';\n/,""),n=n.replace(/const withNextIntl = createNextIntlPlugin\(\);\n/,""),n=n.replace(/export default withNextIntl\(nextConfig\);/,"export default nextConfig;"),await u(s,n)}let o=f.join(e,a.COUNTER_COMPONENT);if(l(o)){let n=await d(o);n=n.replace(/import\s+\{\s*useTranslations\s*\}\s+from\s+['"]next-intl['"];\n/,""),n=n.replace(/\s*const\s+t\s*=\s*useTranslations\(['"]Count['"]\);\n/,""),n=n.replace(/\{t\('currentCount',\s*\{\s*count:\s*value\s*\}\)\}/g,"{value}"),n=n.replace(/\{t\(['"]increment['"]\)\}/g,"Increment"),n=n.replace(/\{t\(['"]decrement['"]\)\}/g,"Decrement"),n=n.replace(/\{t\(['"]reset['"]\)\}/g,"Reset"),await u(o,n)}}},Pi=async e=>{await v(f.join(e,a.LICENSE))},Si=async e=>{await v(f.join(e,a.CHANGELOG))},vi=async e=>{await v(f.join(e,a.NVM_RC)),await v(f.join(e,a.NPM_RC))};import Se from"node:path";I();var Ue=async(e,i)=>{let t=[],r=[];i.redux&&(t.push("import { StoreProvider } from '@/providers';"),r.push("StoreProvider")),i.darkMode&&(t.push("import { CustomThemeProvider } from '@/providers';"),r.push("CustomThemeProvider")),i.i18n&&(t.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),t.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
|
|
4
|
+
${t.join(`
|
|
5
5
|
`)}
|
|
6
6
|
|
|
7
7
|
export const RootProvider = ({
|
|
8
8
|
children,
|
|
9
|
-
${
|
|
9
|
+
${i.i18n?`locale,
|
|
10
10
|
messages,`:""}
|
|
11
11
|
}: {
|
|
12
12
|
children: React.ReactNode;
|
|
13
|
-
${
|
|
13
|
+
${i.i18n?`locale: SupportedLocale;
|
|
14
14
|
messages: AbstractIntlMessages;`:""}
|
|
15
15
|
}) => {
|
|
16
16
|
return (
|
|
17
|
-
`,o="{children}";
|
|
17
|
+
`,o="{children}";i.i18n&&(o=`<NextIntlClientProvider locale={locale} messages={messages}>
|
|
18
18
|
${o}
|
|
19
|
-
</NextIntlClientProvider>`),
|
|
19
|
+
</NextIntlClientProvider>`),i.darkMode&&(o=`<CustomThemeProvider>
|
|
20
20
|
${o}
|
|
21
|
-
</CustomThemeProvider>`),
|
|
21
|
+
</CustomThemeProvider>`),i.redux&&(o=`<StoreProvider>
|
|
22
22
|
${o}
|
|
23
23
|
</StoreProvider>`),o==="{children}"&&(o="<>{children}</>"),s+=` ${o}
|
|
24
24
|
);
|
|
25
25
|
};
|
|
26
|
-
`,await u(
|
|
26
|
+
`,await u(Se.join(e,a.ROOT_PROVIDER),s)},Xe=async(e,i)=>{if(!i.i18n){let t=`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: '${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={${
|
|
50
|
-
<body className={\`\${livvic.variable} ${
|
|
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,51 +55,51 @@ export default function RootLayout({
|
|
|
55
55
|
</html>
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
|
-
`;await u(
|
|
58
|
+
`;await u(Se.join(e,a.ROOT_LAYOUT),t);let r=i.redux?`import { Counter } from '@/features/counter';
|
|
59
59
|
|
|
60
|
-
`:"",s=
|
|
61
|
-
<Counter />`:"",o=`${
|
|
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 ${
|
|
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(
|
|
70
|
-
`};s("CONTAINER_NAME",
|
|
69
|
+
`;await u(Se.join(e,a.ROOT_PAGE),o)}};import T from"node:path";import{readdir as Je}from"node:fs/promises";I();var Ye=async(e,i)=>{await Ci(e,i),await wi(e,i),await Ti(e,i),await Ei(e,i),await Ii(e,i),await Ri(e,i),await Ni(e,i)},Ci=async(e,i)=>{i.preCommitHooks||(await h(T.join(e,a.HUSKY_DIR)),await v(T.join(e,a.COMMITLINT_CONFIG)),await v(T.join(e,a.LINTSTAGED_RC)),await te(T.join(e,a.PACKAGE_JSON),t=>(delete t.devDependencies[A.HUSKY],delete t.devDependencies[A.COMMITLINT_CLI],delete t.devDependencies[A.COMMITLINT_CONFIG],delete t.devDependencies[A.LINT_STAGED],delete t.scripts.prepare,delete t.scripts.postinstall,delete t.commitlint,delete t["lint-staged"],t)))},wi=async(e,i)=>{i.commitizen||(await v(T.join(e,a.CZRC)),await te(T.join(e,a.PACKAGE_JSON),t=>(delete t.devDependencies[A.COMMITIZEN],delete t.devDependencies[A.CZ_CONVENTIONAL_CHANGELOG],delete t.config?.commitizen,t.config&&Object.keys(t.config).length===0&&delete t.config,delete t.scripts.commit,t)))},Ti=async(e,i)=>{i.ci||await h(T.join(e,a.GITHUB_WORKFLOWS))},Ei=async(e,i)=>{let t=T.join(e,a.GITHUB_DIR);if(!i.keepTemplates)await h(T.join(t,a.GITHUB_ISSUE_TEMPLATE)),await v(T.join(t,a.GITHUB_PR_TEMPLATE));else{let r=T.join(t,a.GITHUB_ISSUE_TEMPLATE),s=T.join(t,a.GITHUB_PR_TEMPLATE),o=n=>n.replace(/Teispace/g,i.company).replace(/support@teispace\.com/g,i.email).replace(/Next\.js Starter/g,i.projectName).replace(/\[AUTHOR\]/g,i.author).replace(/\[COMPANY\]/g,i.company).replace(/\[EMAIL\]/g,i.email);if(l(s)){let n=await d(s);n=o(n),await u(s,n)}try{if(l(r)){let n=await Je(r);for(let c of n){let p=T.join(r,c),g=await d(p);g=o(g),await u(p,g)}}}catch{}}},Ii=async(e,i)=>{let t=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let r of t)i.communityFiles.includes(r)||await v(T.join(e,r))},Ri=async(e,i)=>{if(i.docker){let t=T.join(e,a.ENV_EXAMPLE);if(l(t)){let r=await d(t),s=(o,n)=>{let c=new RegExp(`${o}=.*`);c.test(r)?r=r.replace(c,`${o}=${n}`):r+=`${o}=${n}
|
|
70
|
+
`};s("CONTAINER_NAME",i.containerName||"next-app"),s("IMAGE_NAME",i.imageName||"nextjs-starter"),s("IMAGE_TAG",i.imageTag||"latest"),await u(t,r)}}else{await v(T.join(e,a.DOCKERFILE)),await v(T.join(e,a.DOCKER_COMPOSE)),await v(T.join(e,a.DOCKERIGNORE));let t=T.join(e,a.ENV_EXAMPLE);if(l(t)){let r=await d(t);r=r.replace(/# Docker Compose Configuration\n/,""),r=r.replace(/CONTAINER_NAME=.*\n/,""),r=r.replace(/IMAGE_NAME=.*\n/,""),r=r.replace(/IMAGE_TAG=.*\n/,""),await u(t,r)}}},Ni=async(e,i)=>{let t=async o=>{let n=await Je(o,{withFileTypes:!0}),c=[];for(let p of n){let g=T.join(o,p.name);p.isDirectory()&&p.name!=="node_modules"&&p.name!==".git"?c.push(...await t(g)):p.isFile()&&p.name.toLowerCase()==="readme.md"&&c.push(g)}return c},r=await t(e),s=T.join(e,a.README);for(let o of r)o!==s&&await v(o);if(i.readme){let o=`# ${i.projectName}
|
|
71
71
|
|
|
72
|
-
${
|
|
72
|
+
${i.description}
|
|
73
73
|
|
|
74
74
|
## Getting Started
|
|
75
75
|
|
|
76
76
|
First, run the development server:
|
|
77
77
|
|
|
78
78
|
\`\`\`bash
|
|
79
|
-
${
|
|
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,o)}else await
|
|
84
|
-
Cleaning up: Deleting directory ${
|
|
85
|
-
Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await
|
|
83
|
+
`;await u(s,o)}else await v(s)};var ze=e=>{e.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async i=>{await Oi(i)})},Oi=async e=>{ke(),m("Welcome to the Teispace Next.js App Creator!"),m("");let i=await be(e),t=ve.resolve(process.cwd(),i.projectName);l(t)&&(console.error(Y.red(`Error: Directory ${i.projectName} already exists.`)),process.exit(1));let r=O("Initializing project..."),s=async()=>{if(l(t)){r.stop(),console.log(Y.yellow(`
|
|
84
|
+
Cleaning up: Deleting directory ${i.projectName}...`));try{await h(t),console.log(Y.green("Cleanup successful."))}catch(n){console.error(Y.red(`Failed to clean up directory ${i.projectName}:`),n)}}},o=async()=>{console.log(Y.red(`
|
|
85
|
+
Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await Le(t),await Ge(t,i),await He(t,i),r.text="Generating code...",await Ue(t,i),await Xe(t,i),r.text="Setting up developer tools...",await Ye(t,i),r.text="Initializing Git...",await je(t,i.gitRemote),r.text="Installing dependencies...",await Fe(t,i.packageManager),r.text="Formatting and Linting...",await L(t,i.packageManager,"format"),await L(t,i.packageManager,"lint:fix"),i.copyEnv){r.text="Creating .env file...";let n=ve.join(t,".env.example"),c=ve.join(t,".env");l(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",o),process.off("SIGTERM",o),r.succeed(Y.green(`Project ${i.projectName} created successfully!`)),m(""),m("To get started:"),m(Y.cyan(` cd ${i.projectName}`)),m(Y.cyan(` ${i.packageManager==="npm"?"npm run dev":i.packageManager+" dev"}`)),m("")}catch(n){r.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import N from"picocolors";import Te from"node:path";import Ai from"enquirer";var{prompt:$i}=Ai,We=async(e,i,t,r,s,o,n)=>{let c=[];e||c.push({type:"input",name:"featureName",message:"What is the feature name?",initial:"my-feature",validate:g=>/^[a-z0-9-]+$/.test(g)?!0:"Feature name must be lowercase and contain only alphanumeric characters and hyphens."}),i&&r===void 0&&s===void 0&&(c.push({type:"confirm",name:"createStore",message:"Generate Redux store for this feature?",initial:!0}),c.push({type:"confirm",name:"persistStore",message:"Enable persistence for this store?",initial:!1,skip(){return!this.state.answers.createStore}})),t&&t!=="none"&&o===void 0&&n===void 0&&(c.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),t==="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 $i(c):{};return{featureName:e||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:t||"none",createService:o===!0?!1:n!==void 0?!0:p.createService||!1,selectedHttpClient:n||p.selectedHttpClient||(t==="both"?"fetch":t!=="none"?t:void 0)}};import{readFile as bi,access as Ce}from"node:fs/promises";import ie from"node:path";var Q=async e=>{let i=!1,t=!1,r=!1,s=!1;try{let o=ie.join(e,"package.json"),n=await bi(o,"utf-8"),c=JSON.parse(n),p={...c.dependencies,...c.devDependencies};i=!!(p["@reduxjs/toolkit"]&&p["react-redux"]),t=!!p.axios,s=!!p["next-intl"];let g=ie.join(e,"src","lib","utils","http","axios-client");try{await Ce(g),t=t&&!0}catch{t=!1}let S=ie.join(e,"src","lib","utils","http","fetch-client");try{await Ce(S),r=!0}catch{r=!1}let P;return t&&r?P="both":t?P="axios":r?P="fetch":P="none",{hasRedux:i,httpClient:P,hasI18n:s}}catch(o){throw new Error(`Failed to detect project setup: ${o}`)}},Ve=async(e,i,t=ie.join("src","features"))=>{let r=ie.join(e,t,i);try{return await Ce(r),!0}catch{return!1}};import{writeFile as H,mkdir as oe}from"node:fs/promises";import b from"node:path";var Be=async e=>{let{featurePath:i}=e;await oe(b.join(i,"components"),{recursive:!0}),await oe(b.join(i,"hooks"),{recursive:!0}),await oe(b.join(i,"types"),{recursive:!0}),e.createStore&&await oe(b.join(i,"store"),{recursive:!0}),e.createService&&await oe(b.join(i,"services"),{recursive:!0}),await _i(e),await ji(e),await Fi(e),await Li(e),e.createStore&&await ki(e),e.createService&&e.httpClient&&await Di(e)};var _i=async e=>{let{featureName:i,featurePath:t}=e,r=J(i),s=`use${r}`,o=`'use client';
|
|
86
86
|
import { ${s} } from '../hooks/${s}';
|
|
87
87
|
|
|
88
|
-
export function ${
|
|
88
|
+
export function ${r}() {
|
|
89
89
|
const {} = ${s}();
|
|
90
90
|
|
|
91
91
|
return (
|
|
92
92
|
<div>
|
|
93
|
-
<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 ${
|
|
100
|
-
`;await
|
|
99
|
+
export default ${r};
|
|
100
|
+
`;await H(b.join(t,"components",`${r}.tsx`),o)},ji=async e=>{let{featureName:i,featurePath:t,createStore:r}=e,s=J(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/${
|
|
102
|
+
import { select${s}State, setLoading, setError } from '../store/${i}.selectors';
|
|
103
103
|
|
|
104
104
|
export const ${o} = () => {
|
|
105
105
|
const dispatch = useAppDispatch();
|
|
@@ -133,13 +133,13 @@ export const ${o} = () => {
|
|
|
133
133
|
// Add your methods here
|
|
134
134
|
} as const;
|
|
135
135
|
};
|
|
136
|
-
`,await
|
|
136
|
+
`,await H(b.join(t,"hooks",`${o}.ts`),n)},Fi=async e=>{let{featureName:i,featurePath:t,createStore:r}=e,n=`export interface ${`${J(i)}State`} {
|
|
137
137
|
// Add your state properties here
|
|
138
|
-
${
|
|
138
|
+
${r?`loading: boolean;
|
|
139
139
|
error: string | null;`:"// example: value: string;"}
|
|
140
140
|
}
|
|
141
|
-
`;await
|
|
142
|
-
import { ${s}State } from '../types/${
|
|
141
|
+
`;await H(b.join(t,"types",`${i}.types.ts`),n)},ki=async e=>{let{featureName:i,featurePath:t,persistStore:r}=e,s=J(i),o=j(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,
|
|
@@ -167,23 +167,23 @@ export const ${o}Slice = createSlice({
|
|
|
167
167
|
export const { setLoading, setError, resetState } = ${o}Slice.actions;
|
|
168
168
|
|
|
169
169
|
export const ${o}Reducer = ${o}Slice.reducer;
|
|
170
|
-
`;await
|
|
170
|
+
`;await H(b.join(t,"store",`${i}.slice.ts`),n);let c=`import { RootState } from '@/store/rootReducer';
|
|
171
171
|
|
|
172
172
|
export const select${s}State = (state: RootState) => state.${o};
|
|
173
|
-
export { setLoading, setError, resetState } from './${
|
|
174
|
-
`;if(await
|
|
173
|
+
export { setLoading, setError, resetState } from './${i}.slice';
|
|
174
|
+
`;if(await H(b.join(t,"store",`${i}.selectors.ts`),c),r){let g=`import { PersistConfig } from 'redux-persist';
|
|
175
175
|
import storage from 'redux-persist/lib/storage';
|
|
176
|
-
import { ${s}State } from '../types/${
|
|
176
|
+
import { ${s}State } from '../types/${i}.types';
|
|
177
177
|
|
|
178
178
|
export const ${o}PersistConfig: PersistConfig<${s}State> = {
|
|
179
179
|
key: '${o}',
|
|
180
180
|
storage,
|
|
181
181
|
// whitelist: ['someField'], // Specify which fields to persist
|
|
182
182
|
};
|
|
183
|
-
`;await
|
|
184
|
-
export * from './${
|
|
183
|
+
`;await H(b.join(t,"store","persist.ts"),g)}let p=`export * from './${i}.slice';
|
|
184
|
+
export * from './${i}.selectors';${r?`
|
|
185
185
|
export * from './persist';`:""}
|
|
186
|
-
`;await
|
|
186
|
+
`;await H(b.join(t,"store","index.ts"),p)},Di=async e=>{let{featureName:i,featurePath:t,httpClient:r}=e,s=j(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
|
|
|
@@ -201,50 +201,50 @@ export const ${s}Service = {
|
|
|
201
201
|
return fetchClient.get<string>(AppApis.${s}.getAll);
|
|
202
202
|
},
|
|
203
203
|
};
|
|
204
|
-
`,await
|
|
204
|
+
`,await H(b.join(t,"services",`${i}.service.ts`),o)},Li=async e=>{let{featureName:i,featurePath:t,createStore:r,createService:s}=e,o=J(i),n=`export { default as ${o} } from './components/${o}';
|
|
205
205
|
export { use${o} } from './hooks/use${o}';
|
|
206
|
-
export * from './types/${
|
|
206
|
+
export * from './types/${i}.types';${r?`
|
|
207
207
|
export * from './store';`:""}${s?`
|
|
208
|
-
export * from './services/${
|
|
209
|
-
`;await
|
|
210
|
-
`+o.slice(
|
|
211
|
-
`+o;let
|
|
208
|
+
export * from './services/${i}.service';`:""}
|
|
209
|
+
`;await H(b.join(t,"index.ts"),n)};import{readFile as Ke,writeFile as qe}from"node:fs/promises";import we from"node:path";var Ze=async(e,i,t,r=we.join("src","features"))=>{let s=we.join(e,"src","store","rootReducer.ts");try{let o=await Ke(s,"utf-8"),n=j(i),c=`${n}Reducer`,p=t?`${n}PersistConfig`:"",g=r.replace(/^src\//,"@/"),S=t?`import { ${c}, ${p} } from '${g}/${i}/store';`:`import { ${c} } from '${g}/${i}/store';`,P=/import\s+.*\s+from\s+['"].*['"];?\n/g,x=o.match(P);if(x&&x.length>0){let R=x[x.length-1],k=o.lastIndexOf(R);o=o.slice(0,k+R.length)+S+`
|
|
210
|
+
`+o.slice(k+R.length)}else o=S+`
|
|
211
|
+
`+o;let w=/combineReducers\(\{([^}]*)\}\)/s,F=o.match(w);if(F){let R=F[1],k=t?`
|
|
212
212
|
${n}: persistReducer(${p}, ${c}),`:`
|
|
213
|
-
${n}: ${c},`,
|
|
214
|
-
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await
|
|
215
|
-
`+o.slice(
|
|
216
|
-
`+o;let
|
|
213
|
+
${n}: ${c},`,Z=R.trimEnd()+k;o=o.replace(w,`combineReducers({${Z}
|
|
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}`)}},Qe=async(e,i,t,r)=>{let s=we.join(e,"src","store","rootReducer.ts");try{let o=await Ke(s,"utf-8"),n=j(i),c=`${n}Reducer`,p=t?`${n}PersistConfig`:"",g=r.replace(/^src\//,"@/"),S=t?`import { ${c}, ${p} } from '${g}/${i}';`:`import { ${c} } from '${g}/${i}';`,P=/import\s+.*\s+from\s+['"].*['"];?\n/g,x=o.match(P);if(x&&x.length>0){let R=x[x.length-1],k=o.lastIndexOf(R);o=o.slice(0,k+R.length)+S+`
|
|
215
|
+
`+o.slice(k+R.length)}else o=S+`
|
|
216
|
+
`+o;let w=/combineReducers\(\{([^}]*)\}\)/s,F=o.match(w);if(F){let R=F[1],k=t?`
|
|
217
217
|
${n}: persistReducer(${p}, ${c}),`:`
|
|
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
|
-
},`,p=/(\s*)\} as const;/;if(!o.match(p))throw new Error("Could not find closing brace of AppApis object");let
|
|
218
|
+
${n}: ${c},`,Z=R.trimEnd()+k;o=o.replace(w,`combineReducers({${Z}
|
|
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 Mi,writeFile as Gi}from"node:fs/promises";import Hi from"node:path";var me=async e=>{let{serviceName:i,projectPath:t}=e,r=j(i),s=Hi.join(t,"src","lib","config","app-apis.ts");try{let o=await Mi(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 S=o.lastIndexOf("} as const;"),P=o.substring(0,S),x=o.substring(S),w=P.trim().endsWith(","),F=P.match(/:\s*\{[^}]*\},\s*$/),R;F||w?R=`${P}
|
|
223
223
|
${c}
|
|
224
|
-
${
|
|
224
|
+
${x}`:R=P.trimEnd()+`
|
|
225
225
|
`+c+`
|
|
226
|
-
`+
|
|
226
|
+
`+x,await Gi(s,R)}catch(o){throw new Error(`Failed to register API endpoints: ${o}`)}};var et=e=>{e.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,t)=>{try{let r=process.cwd();t.store&&!["persist","no-persist"].includes(t.store)&&(E("Invalid --store option. Use: persist or no-persist"),process.exit(1)),t.service&&!["axios","fetch"].includes(t.service)&&(E("Invalid --service option. Use: axios or fetch"),process.exit(1)),t.skipStore&&t.store&&(E("Cannot use --skip-store and --store together"),process.exit(1)),t.skipService&&t.service&&(E("Cannot use --skip-service and --service together"),process.exit(1)),m(N.cyan(`
|
|
227
227
|
\u{1F3AF} Feature Generator
|
|
228
|
-
`)),
|
|
229
|
-
`));let o=await
|
|
228
|
+
`)),y.start("Detecting project setup...");let s=await Q(r);y.succeed("Project setup detected"),m(N.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),m(N.dim(` HTTP Client: ${s.httpClient}`)),m(N.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
|
|
229
|
+
`));let o=await We(i,s.hasRedux,s.httpClient,t.skipStore,t.store,t.skipService,t.service),n=t.path||Te.join("src","features"),c=Te.join(r,n,o.featureName);await Ve(r,o.featureName,n)&&(E(`Feature '${o.featureName}' already exists at ${n}!`),process.exit(1)),y.start("Generating feature files..."),await Be({featureName:o.featureName,featurePath:c,createStore:o.createStore,persistStore:o.persistStore,createService:o.createService,httpClient:o.selectedHttpClient}),y.succeed("Feature files generated"),o.createService&&(y.start("Registering API endpoints..."),await me({serviceName:o.featureName,projectPath:r}),y.succeed("API endpoints registered")),o.createStore&&s.hasRedux&&(y.start("Registering feature in rootReducer..."),await Ze(r,o.featureName,o.persistStore,n),y.succeed("Feature registered in rootReducer"));let g=Te.join(n,o.featureName);m(N.green(`
|
|
230
230
|
\u2728 Feature '${o.featureName}' created successfully!
|
|
231
|
-
`)),
|
|
232
|
-
`)),
|
|
231
|
+
`)),m(N.dim("Generated files:")),m(N.dim(` \u{1F4C2} ${g}/`)),m(N.dim(" \u251C\u2500\u2500 components/")),m(N.dim(" \u251C\u2500\u2500 hooks/")),m(N.dim(" \u251C\u2500\u2500 types/")),o.createStore&&m(N.dim(" \u251C\u2500\u2500 store/")),o.createService&&m(N.dim(" \u251C\u2500\u2500 services/")),m(N.dim(` \u2514\u2500\u2500 index.ts
|
|
232
|
+
`)),m(N.cyan("Next steps:"));let S=n.replace(/^src\//,"@/");m(N.dim(` 1. Import and use the feature: import { ${o.featureName} } from '${S}/${o.featureName}'`)),o.createStore&&m(N.dim(` 2. Customize your Redux slice in: ${g}/store/`)),o.createService&&m(N.dim(` 3. Add API methods in: ${g}/services/${o.featureName}.service.ts`)),m("")}catch(r){y.fail("Feature generation failed"),E(`${r}`),process.exit(1)}})};import _ from"picocolors";import z from"node:path";import{existsSync as qi}from"node:fs";import{mkdir as Zi}from"node:fs/promises";import Ui from"enquirer";var{prompt:Xi}=Ui,tt=async(e,i,t)=>{let r=[];e||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&&t===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=r.length>0?await Xi(r):{};return{sliceName:e||s.sliceName,persistSlice:i===!0?!0:t===!1?!1:s.persistSlice||!1}};import{writeFile as re,mkdir as Ji}from"node:fs/promises";import ne from"node:path";var it=async e=>{let{sliceName:i,slicePath:t,persistSlice:r}=e;await Ji(t,{recursive:!0});let s=J(i),o=j(i);await Yi(i,t,s),await zi(i,t,s,o),await Wi(i,t,s,o),r&&await Vi(i,t,s,o),await Bi(i,t,r)},Yi=async(e,i,t)=>{let r=`export interface ${t}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 re(ne.join(i,`${e}.types.ts`),r)},zi=async(e,i,t,r)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
238
|
+
import { ${t}State } from './${e}.types';
|
|
239
239
|
|
|
240
|
-
const initialState: ${
|
|
240
|
+
const initialState: ${t}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 ${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 ${i}Slice = createSlice({
|
|
|
260
260
|
},
|
|
261
261
|
});
|
|
262
262
|
|
|
263
|
-
export const { setLoading, setError, resetState } = ${
|
|
263
|
+
export const { setLoading, setError, resetState } = ${r}Slice.actions;
|
|
264
264
|
|
|
265
|
-
export const ${
|
|
266
|
-
`;await
|
|
265
|
+
export const ${r}Reducer = ${r}Slice.reducer;
|
|
266
|
+
`;await re(ne.join(i,`${e}.slice.ts`),s)},Wi=async(e,i,t,r)=>{let s=`import { RootState } from '@/store/rootReducer';
|
|
267
267
|
|
|
268
|
-
export const select${
|
|
269
|
-
export { setLoading, setError, resetState } from './${
|
|
270
|
-
`;await
|
|
268
|
+
export const select${t}State = (state: RootState) => state.${r};
|
|
269
|
+
export { setLoading, setError, resetState } from './${e}.slice';
|
|
270
|
+
`;await re(ne.join(i,`${e}.selectors.ts`),s)},Vi=async(e,i,t,r)=>{let s=`import { PersistConfig } from 'redux-persist';
|
|
271
271
|
import storage from 'redux-persist/lib/storage';
|
|
272
|
-
import { ${
|
|
272
|
+
import { ${t}State } from './${e}.types';
|
|
273
273
|
|
|
274
|
-
export const ${
|
|
275
|
-
key: '${
|
|
274
|
+
export const ${r}PersistConfig: PersistConfig<${t}State> = {
|
|
275
|
+
key: '${r}',
|
|
276
276
|
storage,
|
|
277
277
|
// whitelist: ['someField'], // Specify which fields to persist
|
|
278
278
|
};
|
|
279
|
-
`;await
|
|
280
|
-
export * from './${
|
|
281
|
-
export * from './${
|
|
279
|
+
`;await re(ne.join(i,"persist.ts"),s)},Bi=async(e,i,t)=>{let r=`export * from './${e}.slice';
|
|
280
|
+
export * from './${e}.selectors';
|
|
281
|
+
export * from './${e}.types';${t?`
|
|
282
282
|
export * from './persist';`:""}
|
|
283
|
-
`;await
|
|
283
|
+
`;await re(ne.join(i,"index.ts"),r)};import{access as Ki}from"node:fs/promises";import ot from"node:path";var rt=async(e,i,t=ot.join("src","store","slices"))=>{let r=ot.join(e,t,i);try{return await Ki(r),!0}catch{return!1}};var nt=e=>{e.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,t)=>{try{let r=process.cwd();t.persist&&t.noPersist===!0&&(E("Cannot use --persist and --no-persist together"),process.exit(1)),m(_.cyan(`
|
|
284
284
|
\u{1F527} Slice Generator
|
|
285
|
-
`)),
|
|
285
|
+
`)),y.start("Detecting project setup...");let s=await Q(r);y.succeed("Project setup detected"),s.hasRedux||(y.fail("Redux is not setup in this project"),E("Please install @reduxjs/toolkit and react-redux first"),m(_.dim(`
|
|
286
286
|
Run: npm install @reduxjs/toolkit react-redux
|
|
287
|
-
`)),process.exit(1)),
|
|
288
|
-
`));let o=await
|
|
287
|
+
`)),process.exit(1)),m(_.dim(` Redux: \u2713
|
|
288
|
+
`));let o=await tt(i,t.persist,t.noPersist===!0?!1:void 0),n,c,p;if(t.path){let w=t.path.replace(/^src\//,"");w.startsWith("features/")?(c=w.split("/")[1],n=z.join("src","features",c,"store"),p=z.join(r,n,o.sliceName)):(n=z.join("src",w),c=w.split("/")[0],p=z.join(r,n,o.sliceName))}else c=o.sliceName,n=z.join("src","features",c,"store"),p=z.join(r,n,o.sliceName);let g=z.join(r,n);qi(g)||await Zi(g,{recursive:!0}),await rt(r,o.sliceName,n)&&(E(`Slice '${o.sliceName}' already exists at ${n}!`),process.exit(1)),y.start("Generating slice files..."),await it({sliceName:o.sliceName,slicePath:p,persistSlice:o.persistSlice}),y.succeed("Slice files generated"),y.start("Registering slice in rootReducer..."),await Qe(r,o.sliceName,o.persistSlice,n),y.succeed("Slice registered in rootReducer");let P=z.join(n,o.sliceName);m(_.green(`
|
|
289
289
|
\u2728 Slice '${o.sliceName}' created successfully!
|
|
290
|
-
`)),
|
|
291
|
-
`)),
|
|
290
|
+
`)),m(_.dim("Generated files:")),m(_.dim(` \u{1F4C2} ${P}/`)),m(_.dim(` \u251C\u2500\u2500 ${o.sliceName}.slice.ts`)),m(_.dim(` \u251C\u2500\u2500 ${o.sliceName}.selectors.ts`)),o.persistSlice&&m(_.dim(" \u251C\u2500\u2500 persist.ts")),m(_.dim(` \u251C\u2500\u2500 ${o.sliceName}.types.ts`)),m(_.dim(` \u2514\u2500\u2500 index.ts
|
|
291
|
+
`)),m(_.cyan("Next steps:"));let x=n.replace(/^src\//,"@/");m(_.dim(` 1. Import actions: import { setLoading, setError } from '${x}/${o.sliceName}'`)),m(_.dim(" 2. Use in component: dispatch(setLoading(true))")),m("")}catch(r){y.fail("Slice generation failed"),E(`${r}`),process.exit(1)}})};import U from"picocolors";import K from"node:path";import{existsSync as ro}from"node:fs";import{mkdir as no}from"node:fs/promises";import st from"enquirer";var at=async(e,i,t,r)=>{let s=e||(await st.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":t!==void 0?o="fetch":r==="axios"?o="axios":r==="fetch"?o="fetch":r==="both"?o=(await st.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:o="axios",{serviceName:s,httpClient:o}};import{writeFile as Qi}from"node:fs/promises";import eo from"node:path";var ct=async e=>{await to(e)},to=async e=>{let{serviceName:i,servicePath:t,httpClient:r}=e,s=j(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
|
|
|
@@ -306,24 +306,25 @@ export const ${s}Service = {
|
|
|
306
306
|
return fetchClient.get<string>(AppApis.${s}.getAll);
|
|
307
307
|
},
|
|
308
308
|
};
|
|
309
|
-
`;let n=`${
|
|
309
|
+
`;let n=`${i}.service.ts`;await Qi(eo.join(t,n),o)};import{existsSync as io}from"node:fs";import oo from"node:path";var lt=async(e,i,t)=>{let r=oo.join(e,t,`${i}.service.ts`);return io(r)};var pt=e=>{e.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,t)=>{try{let r=process.cwd();t.axios&&t.fetch&&(E("Cannot use --axios and --fetch together"),process.exit(1)),m(U.cyan(`
|
|
310
310
|
\u{1F527} Service Generator
|
|
311
|
-
`)),
|
|
311
|
+
`)),y.start("Detecting project setup...");let s=await Q(r);y.succeed("Project setup detected"),s.httpClient==="none"&&(y.fail("No HTTP client is setup in this project"),E("Please setup either AxiosClient or FetchClient first"),m(U.dim(`
|
|
312
312
|
Check: lib/utils/http/axios-client or lib/utils/http/fetch-client
|
|
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"),
|
|
314
|
-
`));let n=await
|
|
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"),m(U.dim(` HTTP Clients: ${o.join(", ")}
|
|
314
|
+
`));let n=await at(i,t.axios,t.fetch,s.httpClient),c,p,g;if(t.path){let w=t.path.replace(/^src\//,"");w.startsWith("features/")?(p=w.split("/")[1],c=K.join("src","features",p,"services"),g=K.join(r,c)):(c=K.join("src",w),p=w.split("/")[0],g=K.join(r,c))}else p=n.serviceName,c=K.join("src","features",p,"services"),g=K.join(r,c);ro(g)||await no(g,{recursive:!0}),await lt(r,n.serviceName,c)&&(E(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),y.start("Generating service files..."),await ct({serviceName:n.serviceName,servicePath:g,httpClient:n.httpClient}),y.succeed("Service files generated"),y.start("Registering API endpoints..."),await me({serviceName:n.serviceName,projectPath:r}),y.succeed("API endpoints registered");let P=K.join(c,`${n.serviceName}.service.ts`);m(U.green(`
|
|
315
315
|
\u2728 Service '${n.serviceName}' created successfully!
|
|
316
|
-
`)),
|
|
317
|
-
`)),
|
|
318
|
-
`,await u(
|
|
319
|
-
`),
|
|
320
|
-
`+
|
|
321
|
-
|
|
322
|
-
|
|
316
|
+
`)),m(U.dim("Generated files:")),m(U.dim(` \u{1F4C4} ${P}
|
|
317
|
+
`)),m(U.cyan("Next steps:"));let x=c.replace(/^src\//,"@/");m(U.dim(` 1. Import service: import { ${n.serviceName}Service } from '${x}/${n.serviceName}.service'`)),m(U.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),m("")}catch(r){y.fail("Service generation failed"),E(`${r}`),process.exit(1)}})};import he from"picocolors";import Io from"enquirer";import ao from"node:path";import co from"picocolors";import se from"node:path";I();import mt from"node:path";I();var de=async e=>{let i=[mt.join(e,a.ROOT_LAYOUT),mt.join(e,"src/app/[locale]/layout.tsx")];for(let t of i)if(l(t)&&(await d(t)).includes("<body"))return t;for(let t of i)if(l(t))return t;return""};var dt=async e=>{let i=se.join(e,a.THEME_PROVIDER),t=se.join(e,a.GLOBALS_CSS),r=se.join(e,"package.json");if(l(i))return{isSetup:!0,reason:"CustomThemeProvider.tsx exists"};if(l(r)){let s=JSON.parse(await d(r));if(s.dependencies&&s.dependencies["next-themes"]||s.devDependencies&&s.devDependencies["next-themes"])return{isSetup:!0,reason:"next-themes is installed"}}return l(t)&&(await d(t)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},ut=async e=>{let i=se.join(e,a.GLOBALS_CSS),t=se.join(e,a.PROVIDERS_INDEX),r=await de(e);if(!l(i)||!r||!l(t))throw new Error("Project structure mismatch. Ensure src/styles/globals.css, src/app/layout.tsx (or src/app/[locale]/layout.tsx), and src/providers/index.ts exist.");return r};import ft from"node:path";import so from"degit";I();var gt=async(e,i)=>{i.text="Fetching assets from starter repo...",await so("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},xt=async(e,i)=>{let t=ft.join(e,a.THEME_PROVIDER),r=ft.join(i,"src/providers/CustomThemeProvider.tsx");await $(r,t)};import ue from"node:path";I();var ht=async e=>{let i=ue.join(e,a.PROVIDERS_INDEX),t=await d(i);t.includes("CustomThemeProvider")||(t+=`export * from './CustomThemeProvider';
|
|
318
|
+
`,await u(i,t))},yt=async e=>{let i=ue.join(e,"src/providers/RootProvider.tsx");if(l(i)){let t=await d(i),r="'use client';",s=t.includes(r);if(s&&(t=t.replace(r,"").trim()),t.includes("CustomThemeProvider")||(t=t.replace(/import \{ StoreProvider \} from '@\/providers';\n/,`import { StoreProvider, CustomThemeProvider } from '@/providers';
|
|
319
|
+
`),t.includes("CustomThemeProvider")||(t.includes("from '@/providers'")?t=t.replace(/\} from '@\/providers'/,", CustomThemeProvider } from '@/providers'"):t=`import { CustomThemeProvider } from '@/providers';
|
|
320
|
+
`+t)),s&&(t=r+`
|
|
321
|
+
`+t),!t.includes("<CustomThemeProvider>")){if(t.includes("<StoreProvider>"))t=t.replace(/<StoreProvider>/,`<StoreProvider>
|
|
322
|
+
<CustomThemeProvider>`),t=t.replace(/<\/StoreProvider>/,`</CustomThemeProvider>
|
|
323
|
+
</StoreProvider>`);else{let o=t.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];t=t.replace(o[0],`return (
|
|
323
324
|
<CustomThemeProvider>
|
|
324
|
-
|
|
325
|
+
${n}
|
|
325
326
|
</CustomThemeProvider>
|
|
326
|
-
);`)
|
|
327
|
+
);`)}}await u(i,t)}}},Pt=async(e,i)=>{let t=ue.join(e,a.GLOBALS_CSS),r=ue.join(i,"src/styles/globals.css"),s="";if(l(r)){let n=await d(r),c=n.match(/@custom-variant dark \(.*?\);/),p=n.match(/@theme \{[\s\S]*?\}/);c&&(s+=`
|
|
327
328
|
${c[0]}
|
|
328
329
|
`),p&&(s+=`
|
|
329
330
|
${p[0]}
|
|
@@ -334,31 +335,32 @@ ${p[0]}
|
|
|
334
335
|
--color-dark: #202938;
|
|
335
336
|
--color-light: #f5f5f5;
|
|
336
337
|
}
|
|
337
|
-
`);let o=await d(
|
|
338
|
-
`,n);o=o.slice(0,c+1)+s+o.slice(c+1)}else o=s+o;await u(
|
|
339
|
-
`,await u(
|
|
340
|
-
`+
|
|
338
|
+
`);let o=await d(t);if(!o.includes("@custom-variant dark")){if(o.includes("@import")){let n=o.lastIndexOf("@import"),c=o.indexOf(`
|
|
339
|
+
`,n);o=o.slice(0,c+1)+s+o.slice(c+1)}else o=s+o;await u(t,o)}},St=async e=>{let i=await d(e);i.includes("dark:bg-dark")||(i=i.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await u(e,i))};var Ee=async e=>{let i=O("Setting up Dark Theme..."),t=ao.join(e,".next-maker-temp");try{let{isSetup:r,reason:s}=await dt(e);if(r){i.fail(`Dark Theme is already set up (${s}).`);return}let o=await ut(e);await gt(t,i),await xt(e,t),await ht(e),await yt(e),await Pt(e,t),await St(o),i.text="Installing next-themes...",await D(e,"next-themes"),i.text="Formatting code...";let n=await G(e);await L(e,n,"format"),i.succeed(co.green("Dark Theme setup successfully!"))}catch(r){throw i.fail("Failed to setup Dark Theme."),r}finally{await h(t)}};import po from"node:path";import mo from"picocolors";import Ie from"node:path";I();var vt=async e=>{let i=Ie.join(e,a.STORE),t=Ie.join(e,"package.json");if(l(i))return{isSetup:!0,reason:"src/store directory exists"};if(l(t)){let r=JSON.parse(await d(t));if(r.dependencies&&r.dependencies["@reduxjs/toolkit"]||r.devDependencies&&r.devDependencies["@reduxjs/toolkit"])return{isSetup:!0,reason:"@reduxjs/toolkit is installed"}}return{isSetup:!1,reason:""}},Ct=async e=>{let i=Ie.join(e,a.PROVIDERS_INDEX);if(!await de(e)||!l(i))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx (or src/app/[locale]/layout.tsx) and src/providers/index.ts exist.")};import q from"node:path";import lo from"degit";I();import wt from"node:fs/promises";var Tt=async(e,i)=>{i.text="Fetching assets from starter repo...",await lo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},Et=async(e,i)=>{let t=q.join(i,"src/providers/StoreProvider.tsx"),r=q.join(e,a.STORE_PROVIDER);await $(t,r);let s=q.join(i,"src/store"),o=q.join(e,a.STORE);await wt.cp(s,o,{recursive:!0})},It=async(e,i)=>{let t=q.join(i,"src/features/counter"),r=q.join(e,a.COUNTER_FEATURE);await wt.cp(t,r,{recursive:!0});let s=q.join(r,"components/Counter.tsx");if(await l(s)){let o=await d(s);o=o.replace(/import \{ useTranslations \} from 'next-intl';\n?/,""),o=o.replace(/const t = useTranslations\('Count'\);\n?/,""),o=o.replace(/\{t\('currentCount', \{ count: value \}\)\}/g,"Current Count: {value}"),o=o.replace(/\{t\('increment'\)\}/g,"Increment"),o=o.replace(/\{t\('decrement'\)\}/g,"Decrement"),o=o.replace(/\{t\('reset'\)\}/g,"Reset"),await u(s,o)}};import fe from"node:path";I();var Rt=async e=>{let i=fe.join(e,a.PROVIDERS_INDEX),t=await d(i);t.includes("StoreProvider")||(t+=`export * from './StoreProvider';
|
|
340
|
+
`,await u(i,t))},Nt=async e=>{let i=fe.join(e,"src/providers/RootProvider.tsx");if(l(i)){let t=await d(i),r="'use client';",s=t.includes(r);if(s&&(t=t.replace(r,"").trim()),t.includes("StoreProvider")||(t=t.replace(/import \{ (.*?) \} from '@\/providers';/,"import { $1, StoreProvider } from '@/providers';"),t.includes("StoreProvider")||(t.includes("from '@/providers'")?t=t.replace(/\} from '@\/providers'/,", StoreProvider } from '@/providers'"):t=`import { StoreProvider } from '@/providers';
|
|
341
|
+
`+t)),s&&(t=r+`
|
|
342
|
+
`+t),!t.includes("<StoreProvider>")){let o=t.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];t=t.replace(o[0],`return (
|
|
341
343
|
<StoreProvider>
|
|
342
|
-
|
|
344
|
+
${n}
|
|
343
345
|
</StoreProvider>
|
|
344
|
-
);`),await u(
|
|
345
|
-
`+
|
|
346
|
+
);`),await u(i,t)}}}},Ot=async e=>{let i=[fe.join(e,a.ROOT_PAGE),fe.join(e,"src/app/[locale]/page.tsx")],t="";for(let r of i)if(l(r)){t=r;break}if(t){let r=await d(t);if(r.includes("Counter")||(r=`import { Counter } from '@/features/counter/components/Counter';
|
|
347
|
+
`+r),!r.includes("<Counter />")){let s=r.lastIndexOf("</div>"),o=r.lastIndexOf("</main>"),n=o!==-1?o:s;n!==-1&&(r=r.slice(0,n)+`
|
|
346
348
|
<div className="mt-8">
|
|
347
349
|
<h2 className="text-2xl font-bold mb-4">Redux Counter</h2>
|
|
348
350
|
<Counter />
|
|
349
351
|
</div>
|
|
350
|
-
`+
|
|
351
|
-
`+
|
|
352
|
+
`+r.slice(n),await u(t,r))}}};var Re=async e=>{let i=O("Setting up Redux Toolkit..."),t=po.join(e,".next-maker-temp-redux");try{let{isSetup:r,reason:s}=await vt(e);if(r){i.fail(`Redux is already set up (${s}).`);return}await Ct(e),await Tt(t,i),i.text="Copying Redux files...",await Et(e,t),i.text="Creating Counter feature...",await It(e,t),i.text="Updating providers and pages...",await Rt(e),await Nt(e),await Ot(e),i.text="Installing dependencies...",await D(e,"@reduxjs/toolkit"),await D(e,"react-redux"),await D(e,"redux-persist"),await D(e,"react-secure-storage"),i.text="Formatting code...";let o=await G(e);await L(e,o,"format"),i.succeed(mo.green("Redux Toolkit setup successfully!"))}catch(r){throw i.fail("Failed to setup Redux Toolkit."),r}finally{await h(t)}};import xo from"node:path";import ho from"picocolors";import ge from"node:path";I();var At=async e=>{let i=ge.join(e,a.I18N_DIR),t=ge.join(e,"package.json");if(l(i))return{isSetup:!0,reason:"src/i18n directory exists"};if(l(t)){let r=JSON.parse(await d(t));if(r.dependencies&&r.dependencies["next-intl"]||r.devDependencies&&r.devDependencies["next-intl"])return{isSetup:!0,reason:"next-intl is installed"}}return{isSetup:!1,reason:""}},$t=async e=>{let i=ge.join(e,a.ROOT_LAYOUT),t=ge.join(e,"src/app/[locale]/layout.tsx");if(!l(i)&&!l(t))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx exists.")};import W from"node:path";import uo from"degit";I();import fo from"node:fs/promises";var bt=async(e,i)=>{i.text="Fetching assets from starter repo...",await uo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},_t=async(e,i)=>{let t=W.join(i,"src/i18n"),r=W.join(e,a.I18N_DIR);await fo.cp(t,r,{recursive:!0});let s=W.join(i,"src/proxy.ts"),o=W.join(e,a.PROXY);await $(s,o);let n=W.join(i,"src/types/i18n.ts"),c=W.join(e,a.I18N_TYPES);await $(n,c);let p=W.join(i,"src/lib/config/app-locales.ts"),g=W.join(e,a.APP_LOCALES);await $(p,g)};import X from"node:path";I();import go from"node:fs/promises";var jt=async e=>{let i=X.join(e,a.NEXT_CONFIG);if(l(i)){let t=await d(i);if(!t.includes("createNextIntlPlugin")){t=`import createNextIntlPlugin from 'next-intl/plugin';
|
|
353
|
+
`+t;let r=/export default (.*?);/;r.test(t)?t=t.replace(r,`
|
|
352
354
|
const withNextIntl = createNextIntlPlugin();
|
|
353
|
-
export default withNextIntl($1);`):(
|
|
355
|
+
export default withNextIntl($1);`):(t+=`
|
|
354
356
|
const withNextIntl = createNextIntlPlugin();
|
|
355
|
-
`,
|
|
356
|
-
`),await u(
|
|
357
|
-
`,await u(
|
|
358
|
-
`,await u(
|
|
357
|
+
`,t+=`export default withNextIntl(nextConfig);
|
|
358
|
+
`),await u(i,t)}}},Ft=async e=>{let i=X.join(e,a.TYPES_INDEX);if(l(i)){let t=await d(i);t.includes("./i18n")||(t+=`export * from './i18n';
|
|
359
|
+
`,await u(i,t))}},kt=async e=>{let i=X.join(e,a.CONFIG_INDEX);if(l(i)){let t=await d(i);t.includes("./app-locales")||(t+=`export * from './app-locales';
|
|
360
|
+
`,await u(i,t))}},Dt=async e=>{let i=X.join(e,"src/providers/RootProvider.tsx");if(l(i)){let t=await d(i),r="'use client';",s=t.includes(r);if(s&&(t=t.replace(r,"").trim()),t.includes("next-intl")||(t=`import { SupportedLocale } from '@/types/i18n';
|
|
359
361
|
import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';
|
|
360
|
-
`+
|
|
361
|
-
`+
|
|
362
|
+
`+t),s&&(t=r+`
|
|
363
|
+
`+t),!t.includes("locale: SupportedLocale")){let o=/export const RootProvider = \(\{([\s\S]*?)\}: \{([\s\S]*?)\}\) => \{/,n=t.match(o);n&&(t=t.replace(n[0],`export const RootProvider = ({
|
|
362
364
|
children,
|
|
363
365
|
locale,
|
|
364
366
|
messages,
|
|
@@ -366,9 +368,15 @@ import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';
|
|
|
366
368
|
children: React.ReactNode;
|
|
367
369
|
locale: SupportedLocale;
|
|
368
370
|
messages: AbstractIntlMessages;
|
|
369
|
-
}) => {`))}
|
|
371
|
+
}) => {`))}if(!t.includes("<NextIntlClientProvider")){let o=t.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];if(n.includes("{children}")){let c=n.replace("{children}",`<NextIntlClientProvider locale={locale} messages={messages}>
|
|
370
372
|
{children}
|
|
371
|
-
</NextIntlClientProvider>`)
|
|
373
|
+
</NextIntlClientProvider>`);t=t.replace(o[0],`return (
|
|
374
|
+
${c}
|
|
375
|
+
);`)}else t=t.replace(o[0],`return (
|
|
376
|
+
<NextIntlClientProvider locale={locale} messages={messages}>
|
|
377
|
+
${n}
|
|
378
|
+
</NextIntlClientProvider>
|
|
379
|
+
);`)}}await u(i,t)}},Lt=async e=>{let i=X.join(e,a.ROOT_LAYOUT),t=X.join(e,a.ROOT_PAGE),r=X.join(e,"src/app/[locale]");if(await go.mkdir(r,{recursive:!0}),l(i)){let s=X.join(r,"layout.tsx"),o=await d(i);if(o.includes("next-intl")||(o=`import { routing } from '@/i18n/routing';
|
|
372
380
|
import { hasLocale } from 'next-intl';
|
|
373
381
|
import { notFound } from 'next/navigation';
|
|
374
382
|
import { setRequestLocale, getMessages } from 'next-intl/server';
|
|
@@ -379,7 +387,7 @@ export function generateStaticParams() {
|
|
|
379
387
|
}`+o.slice(g)}}o=o.replace(/Readonly<\{\s*children:\s*React\.ReactNode;\s*}>/,`Readonly<{
|
|
380
388
|
children: React.ReactNode;
|
|
381
389
|
params: Promise<{ locale: string }>;
|
|
382
|
-
}>`);let n=/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,c=o.match(n);if(c){c[1]||(o=o.replace("export default function","export default async function")),o=o.replace(/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,"export default async function RootLayout({ children, params }:");let g=/export default async function RootLayout[\s\S]*?\)\s*\{/,
|
|
390
|
+
}>`);let n=/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,c=o.match(n);if(c){c[1]||(o=o.replace("export default function","export default async function")),o=o.replace(/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,"export default async function RootLayout({ children, params }:");let g=/export default async function RootLayout[\s\S]*?\)\s*\{/,S=o.match(g);if(S&&S.index!==void 0){let P=S.index+S[0].length-1;o=o.slice(0,P+1)+`
|
|
383
391
|
const { locale } = await params;
|
|
384
392
|
|
|
385
393
|
if (!hasLocale(routing.locales, locale)) {
|
|
@@ -389,7 +397,7 @@ export function generateStaticParams() {
|
|
|
389
397
|
setRequestLocale(locale);
|
|
390
398
|
|
|
391
399
|
const messages = await getMessages();
|
|
392
|
-
`+o.slice(
|
|
400
|
+
`+o.slice(P+1)}o=o.replace(/<RootProvider>/,"<RootProvider locale={locale} messages={messages}>"),o=o.replace(/<html lang="en"/,"<html lang={locale}")}await u(s,o),await v(i)}if(l(t)){let s=X.join(r,"page.tsx"),o=await d(t);o.includes("next-intl")||(o=`import { SupportedLocale } from '@/types/i18n';
|
|
393
401
|
import { setRequestLocale } from 'next-intl/server';
|
|
394
402
|
`+o),o=o.replace(/export default function Home\(\)/,`type Props = {
|
|
395
403
|
params: Promise<{ locale: string }>;
|
|
@@ -398,9 +406,17 @@ import { setRequestLocale } from 'next-intl/server';
|
|
|
398
406
|
export default async function Home(props: Props)`);let n=o.indexOf("export default async function Home(props: Props) {");if(n!==-1){let c=`
|
|
399
407
|
const locale = (await props.params).locale as SupportedLocale;
|
|
400
408
|
setRequestLocale(locale);
|
|
401
|
-
`,p=o.indexOf("{",n);o=o.slice(0,p+1)+c+o.slice(p+1)}await u(s,o),await
|
|
409
|
+
`,p=o.indexOf("{",n);o=o.slice(0,p+1)+c+o.slice(p+1)}await u(s,o),await v(t)}};var Ne=async e=>{let i=O("Setting up Internationalization (next-intl)..."),t=xo.join(e,".next-maker-temp-i18n");try{let{isSetup:r,reason:s}=await At(e);if(r){i.fail(`i18n is already set up (${s}).`);return}await $t(e),await bt(t,i),i.text="Copying i18n files...",await _t(e,t),i.text="Configuring project structure...",await jt(e),await Ft(e),await kt(e),await Dt(e),i.text="Migrating to [locale] structure...",await Lt(e),i.text="Installing dependencies...",await D(e,"next-intl"),i.text="Formatting code...";let o=await G(e);await L(e,o,"format"),i.succeed(ho.green("Internationalization setup successfully!"))}catch(r){throw i.fail("Failed to setup Internationalization."),r}finally{await h(t)}};import Oe from"node:path";import Co from"node:fs/promises";import Ae from"picocolors";import xe from"enquirer";import ae from"node:path";I();var Mt=async e=>{let i=ae.join(e,a.FETCH_CLIENT_FILE),t=ae.join(e,a.AXIOS_CLIENT_FILE),r=l(i),s=l(t);return r&&s?{status:"both",reason:"Both Fetch and Axios clients are detected"}:r?{status:"fetch",reason:"Fetch client is already setup"}:s?{status:"axios",reason:"Axios client is already setup"}:{status:"none"}},Gt=async e=>{let t=[ae.join(e,"src/lib"),ae.join(e,"src/types"),ae.join(e,"src/lib/config")].filter(r=>!l(r));if(t.length>0)throw new Error(`Invalid project structure. Missing directories:
|
|
410
|
+
${t.map(r=>`- ${r}`).join(`
|
|
411
|
+
`)}`)};import C from"node:path";import yo from"degit";I();import ee from"node:fs/promises";var Ht=async(e,i)=>{i.text="Downloading assets from starter repository...",await yo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},Ut=async(e,i,t,r)=>{let s=C.join(e,a.HTTP_UTILS),o=C.join(i,a.HTTP_UTILS);await ee.cp(C.join(i,a.ERRORS_DIR),C.join(e,a.ERRORS_DIR),{recursive:!0}),await $(C.join(i,a.APP_APIS),C.join(e,a.APP_APIS)),await $(C.join(i,a.CONSTANTS),C.join(e,a.CONSTANTS));let n=C.join(e,a.STORAGE_SERVICE);if(l(n)||await ee.cp(C.join(i,a.STORAGE_SERVICE),n,{recursive:!0}),await ee.cp(C.join(i,a.COMMON_TYPES_DIR),C.join(e,a.COMMON_TYPES_DIR),{recursive:!0}),await ee.cp(C.join(i,a.UTILITY_TYPES_DIR),C.join(e,a.UTILITY_TYPES_DIR),{recursive:!0}),await $(C.join(o,"token-store.ts"),C.join(s,"token-store.ts")),await $(C.join(o,"client-utils.ts"),C.join(s,"client-utils.ts")),r&&r.length>0)for(let c of r){let p=C.join(e,c==="fetch"?a.FETCH_CLIENT:a.AXIOS_CLIENT);await h(p)}for(let c of t)c==="fetch"?await ee.cp(C.join(i,a.FETCH_CLIENT),C.join(e,a.FETCH_CLIENT),{recursive:!0}):await ee.cp(C.join(i,a.AXIOS_CLIENT),C.join(e,a.AXIOS_CLIENT),{recursive:!0});await $(C.join(o,"index.ts"),C.join(s,"index.ts")),await $(C.join(i,a.HTTP_TYPES),C.join(e,a.HTTP_TYPES))};import ce from"node:path";I();import{exec as Po}from"node:child_process";import{promisify as So}from"node:util";var vo=So(Po),Xt=async(e,i)=>{let t=ce.join(e,a.HTTP_UTILS,"index.ts");if(l(t)){let r=await d(t);r=r.replace(/export .* from '\.\/axios-client';?\n?/g,""),r=r.replace(/export .* from '\.\/fetch-client';?\n?/g,""),i.includes("fetch")&&!r.includes("fetch-client")&&(r+=`export * from './fetch-client';
|
|
412
|
+
`),i.includes("axios")&&!r.includes("axios-client")&&(r+=`export * from './axios-client';
|
|
413
|
+
`),await u(t,r)}},Jt=async e=>{let i=ce.join(e,a.UTILS_INDEX);if(l(i)){let t=await d(i);t.includes("./http")||(t+=`export * from './http';
|
|
414
|
+
`,await u(i,t))}},Yt=async e=>{let i=ce.join(e,a.TYPES_INDEX);if(l(i)){let t=await d(i);t.includes("./common")||(t+=`export * from './common';
|
|
415
|
+
`),t.includes("./utility")||(t+=`export * from './utility';
|
|
416
|
+
`),await u(i,t)}},zt=async e=>{let i=ce.join(e,a.CONFIG_INDEX);if(l(i)){let t=await d(i);t.includes("./app-apis")||(t+=`export * from './app-apis';
|
|
417
|
+
`,await u(i,t))}},Wt=async(e,i,t)=>{if(i===t)return;let r=i==="fetch"?"fetchClient":"axiosClient",s=t==="fetch"?"fetchClient":"axiosClient",o=i==="fetch"?"fetch-client":"axios-client",n=t==="fetch"?"fetch-client":"axios-client",c=ce.join(e,"src");try{let p=`grep -rl "${r}" "${c}" --include="*.ts" --include="*.tsx" || true`,{stdout:g}=await vo(p);if(!g.trim())return;let S=g.trim().split(`
|
|
418
|
+
`).filter(P=>P);for(let P of S){if(!l(P))continue;let x=await d(P),w=!1,F=new RegExp(`(import\\s*\\{[^}]*?)\\b${r}\\b([^}]*?\\}\\s*from\\s*['"][^'"]*?/http['"])`,"g");F.test(x)&&(x=x.replace(F,`$1${s}$2`),w=!0);let R=new RegExp(`import\\s+${r}\\s+from\\s+['"]([^'"]*?)/${o}['"]`,"g");R.test(x)&&(x=x.replace(R,`import ${s} from '$1/${n}'`),w=!0);let k=new RegExp(`\\b${r}\\b(?=\\.)`,"g");k.test(x)&&(x=x.replace(k,s),w=!0);let Z=new RegExp(`\\b${r}\\b(?![.\\w])`,"g");Z.test(x)&&(x=x.replace(Z,s),w=!0),w&&await u(P,x)}}catch(p){console.warn("Warning: Could not scan for HTTP client usages:",p)}};var $e=async e=>{let i=O("Checking HTTP Client setup..."),t=Oe.join(e,".next-maker-temp-http");try{let{status:r,reason:s}=await Mt(e);i.stop();let o=await wo(r,s);if(o.type==="cancel"){console.log(Ae.yellow("Setup cancelled."));return}if(i.start("Setting up HTTP client(s)..."),await Gt(e),await Ht(t,i),o.type==="replace"&&o.fromClient&&(i.text="Migrating client usages...",await Wt(e,o.fromClient,o.clients[0])),o.type!=="remove-both"&&o.type!=="remove-one"){i.text="Copying client files...";let S=o.type==="replace"&&o.fromClient?[o.fromClient]:void 0;await Ut(e,t,o.clients,S)}if(o.type==="remove-one"||o.type==="remove-both"){i.text="Removing client files...";let{PROJECT_PATHS:S}=await Promise.resolve().then(()=>(I(),Me));for(let P of o.clients){let x=Oe.join(e,P==="fetch"?S.FETCH_CLIENT:S.AXIOS_CLIENT);await h(x)}}if(o.type!=="remove-both"){i.text="Configuring client...";let S=To(r,o);await Xt(e,S),await Jt(e),await Yt(e),await zt(e)}o.clients.includes("axios")&&(o.type==="install"||o.type==="add")&&(i.text="Installing Axios...",await D(e,"axios"));let n=Oe.join(e,"package.json"),c=JSON.parse(await Co.readFile(n,"utf-8"));!(c.dependencies?.["react-secure-storage"]||c.devDependencies?.["react-secure-storage"])&&o.type!=="remove-both"&&(i.text="Installing react-secure-storage (for token storage)...",await D(e,"react-secure-storage")),i.text="Formatting code...";let g=await G(e);await L(e,g,"format"),i.succeed(Ae.green(Eo(o)))}catch(r){throw i.fail("Failed to setup HTTP Client."),r}finally{await h(t)}};async function wo(e,i){if(e==="none"){let{choice:r}=await xe.prompt({type:"select",name:"choice",message:"Which HTTP client(s) do you want to setup?",choices:[{name:"fetch",message:"Fetch (Native)"},{name:"axios",message:"Axios"},{name:"both",message:"Both (Fetch + Axios)"}]});return r==="both"?{type:"install",clients:["fetch","axios"]}:{type:"install",clients:[r]}}if(e==="fetch"){let{action:r}=await xe.prompt({type:"select",name:"action",message:`${i}. What would you like to do?`,choices:[{name:"cancel",message:"Keep Fetch only (cancel)"},{name:"add",message:"Add Axios (have both)"},{name:"replace",message:"Replace with Axios only"},{name:"remove",message:"Remove Fetch"}]});if(r==="cancel")return{type:"cancel",clients:[]};if(r==="add")return{type:"add",clients:["axios"]};if(r==="replace")return{type:"replace",clients:["axios"],fromClient:"fetch"};if(r==="remove")return{type:"remove-one",clients:["fetch"]}}if(e==="axios"){let{action:r}=await xe.prompt({type:"select",name:"action",message:`${i}. What would you like to do?`,choices:[{name:"cancel",message:"Keep Axios only (cancel)"},{name:"add",message:"Add Fetch (have both)"},{name:"replace",message:"Replace with Fetch only"},{name:"remove",message:"Remove Axios"}]});if(r==="cancel")return{type:"cancel",clients:[]};if(r==="add")return{type:"add",clients:["fetch"]};if(r==="replace")return{type:"replace",clients:["fetch"],fromClient:"axios"};if(r==="remove")return{type:"remove-one",clients:["axios"]}}console.log(Ae.yellow(`\u2716 ${i}`));let{action:t}=await xe.prompt({type:"select",name:"action",message:"What would you like to do?",choices:[{name:"cancel",message:"Keep both (cancel)"},{name:"remove-fetch",message:"Remove Fetch (keep Axios)"},{name:"remove-axios",message:"Remove Axios (keep Fetch)"},{name:"remove-both",message:"Remove both"}]});return t==="cancel"?{type:"cancel",clients:[]}:t==="remove-fetch"?{type:"remove-one",clients:["fetch"]}:t==="remove-axios"?{type:"remove-one",clients:["axios"]}:t==="remove-both"?{type:"remove-both",clients:["fetch","axios"]}:{type:"cancel",clients:[]}}function To(e,i){return i.type==="install"?i.clients:i.type==="add"?[...e==="fetch"?["fetch"]:["axios"],...i.clients]:i.type==="replace"?i.clients:i.type==="remove-one"?e==="both"?i.clients[0]==="fetch"?["axios"]:["fetch"]:[]:[]}function Eo(e){if(e.type==="install")return`HTTP Client (${e.clients.map(t=>t==="fetch"?"Fetch":"Axios").join(" + ")}) setup successfully!`;if(e.type==="add")return`${e.clients[0]==="fetch"?"Fetch":"Axios"} client added successfully! Both clients are now available.`;if(e.type==="replace"){let i=e.fromClient==="fetch"?"Fetch":"Axios",t=e.clients[0]==="fetch"?"Fetch":"Axios";return`Replaced ${i} with ${t} successfully! Imports automatically migrated.`}return e.type==="remove-one"?`${e.clients[0]==="fetch"?"Fetch":"Axios"} client removed successfully!`:e.type==="remove-both"?"Both HTTP clients removed successfully!":"HTTP Client setup completed!"}var{prompt:Ro}=Io,Vt=e=>{e.command("setup").description("Setup features in an existing Next.js project").option("--http-client","Setup HTTP client (axios|fetch)").option("--dark-theme","Setup Dark Theme (Tailwind + next-themes)").option("--redux","Setup Redux Toolkit").option("--i18n","Setup next-intl for internationalization").action(async i=>{try{if(m(he.cyan(`
|
|
402
419
|
\u{1F527} Setup Wizard
|
|
403
|
-
`))
|
|
404
|
-
\u26A0\uFE0F ${
|
|
405
|
-
\u26A0\uFE0F HTTP Client setup is not implemented yet.`)),l(q.dim("This feature will be available in a future update."))),r.darkTheme&&await Se(process.cwd()),r.redux&&await ve(process.cwd()),r.i18n&&await Ce(process.cwd())}catch(e){x.fail("Setup failed"),C(`${e}`),process.exit(1)}})};var $t=t=>{Fe(t),Ot(t),ze(t),Be(t),et(t)};async function Zr(){Ne({logger:r=>ne(r)});let t=new qr;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),$t(t),t.parse()}Zr().catch(t=>{let r=t&&typeof t=="object"&&"message"in t?t.message:String(t);ne(`Unexpected error: ${r}`)});
|
|
420
|
+
`)),i.httpClient||i.darkTheme||i.redux||i.i18n){i.httpClient&&await $e(process.cwd()),i.darkTheme&&await Ee(process.cwd()),i.redux&&await Re(process.cwd()),i.i18n&&await Ne(process.cwd());return}let r=(await Ro([{type:"select",name:"feature",message:"What would you like to setup?",choices:[{name:"Dark Theme",value:"dark-theme"},{name:"Redux Toolkit",value:"redux"},{name:"HTTP Client (Axios/Fetch)",value:"http-client"},{name:"Internationalization (next-intl)",value:"i18n"},"Cancel"]}])).feature;if(r==="Cancel"){m(he.yellow("Setup cancelled."));return}r==="dark-theme"?await Ee(process.cwd()):r==="redux"?await Re(process.cwd()):r==="http-client"?await $e(process.cwd()):r==="i18n"?await Ne(process.cwd()):(m(he.yellow(`
|
|
421
|
+
\u26A0\uFE0F ${r} setup is not implemented yet.`)),m(he.dim("This feature will be available in a future update.")))}catch(t){y.fail("Setup failed"),E(`${t}`),process.exit(1)}})};var Bt=e=>{ze(e),Vt(e),et(e),nt(e),pt(e)};var Oo=process.emitWarning;process.emitWarning=function(e,i,t,r){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return Oo.apply(process,arguments)};async function Ao(){De({logger:i=>pe(i)});let e=new No;e.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),Bt(e),e.parse()}Ao().catch(e=>{let i=e&&typeof e=="object"&&"message"in e?e.message:String(e);pe(`Unexpected error: ${i}`)});
|
|
406
422
|
//# sourceMappingURL=index.js.map
|