@teispace/next-maker 1.7.0 → 1.9.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 -121
- package/dist/index.js.map +4 -4
- package/dist/src/services/setup/http-client/assets.d.ts.map +1 -1
- package/dist/src/services/setup/http-client/index.d.ts.map +1 -1
- package/dist/src/services/setup/http-client/injectors.d.ts +14 -0
- package/dist/src/services/setup/http-client/injectors.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var ii=Object.defineProperty;var oi=(e,i)=>()=>(e&&(i=e(e=0)),i);var ri=(e,i)=>{for(var t in i)ii(e,t,{get:i[t],enumerable:!0})};var Ge={};ri(Ge,{PROJECT_PATHS:()=>a});var a,I=oi(()=>{"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 jo}from"commander";import Te from"node:path";import W from"picocolors";import ni from"ora";function O(e="",i){let t=ni({text:e,...i});return t.start(),t}import si from"enquirer";var{prompt:ai}=si,je=async e=>{let i=await ai([{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 K from"node:fs/promises";import Fe from"node:path";import{existsSync as ve}from"node:fs";var m=async e=>K.readFile(e,"utf-8"),d=async(e,i)=>{await K.mkdir(Fe.dirname(e),{recursive:!0}),await K.writeFile(e,i,"utf-8")},$=async(e,i)=>{await K.mkdir(Fe.dirname(i),{recursive:!0}),await K.copyFile(e,i)},w=async e=>{ve(e)&&await K.unlink(e)},x=async e=>{ve(e)&&await K.rm(e,{recursive:!0,force:!0})},ie=async(e,i)=>{let t=await m(e),r=JSON.parse(t),s=i(r);await d(e,JSON.stringify(s,null,2))},l=e=>ve(e);import{exec as ci}from"node:child_process";import{promisify as li}from"node:util";var pe=li(ci),ke=async(e,i)=>{try{await pe("git init",{cwd:e}),await pe("git add .",{cwd:e}),await pe('git commit -m "Initial commit from @teispace/next-maker"',{cwd:e}),i&&await pe(`git remote add origin ${i}`,{cwd:e})}catch(t){console.warn("Failed to initialize git repository",t)}};import{exec as pi}from"node:child_process";import{promisify as mi}from"node:util";var me=mi(pi),De=async(e,i)=>{let t=`${i} install`;try{await me(t,{cwd:e})}catch(r){throw new Error(`Failed to install dependencies with ${i}: ${r}`)}},M=async(e,i,t)=>{let r=i==="npm"?`${i} run ${t}`:`${i} ${t}`;try{await me(r,{cwd:e})}catch(s){console.warn(`Warning: Failed to run script '${t}': ${s}`)}},di=()=>{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"},H=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":di()},ui=async(e,i,t)=>{if(t.length===0)return;let s=`${fi(i)} ${t.join(" ")}`;try{await me(s,{cwd:e})}catch(o){throw new Error(`Failed to install packages with ${i}: ${o}`)}},fi=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 H(e);await ui(e,t,[i])},gi=async(e,i,t)=>{if(t.length===0)return;let s=`${xi(i)} ${t.join(" ")}`;try{await me(s,{cwd:e})}catch(o){throw new Error(`Failed to uninstall packages with ${i}: ${o}`)}},xi=e=>{switch(e){case"npm":return"npm uninstall";case"yarn":return"yarn remove";case"pnpm":return"pnpm remove";case"bun":return"bun remove";default:return"npm uninstall"}},Ce=async(e,i)=>{let t=await H(e);await gi(e,t,[i])};import G from"picocolors";var hi={reset:e=>e,red:G.red,green:G.green,yellow:G.yellow,blue:G.blue,cyan:G.cyan,magenta:G.magenta,white:G.white,gray:G.gray,bright:G.bold,dim:G.dim};function q(e,i="reset"){let t=hi[i]??(r=>r);console.log(t(e))}function de(e){q(`\u2716 ${e}`,"red")}var E=de;function u(e){q(e)}function Le(){console.log(""),q("\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"),q("\u2551 \u2551","cyan"),q("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),q("\u2551 \u2551","cyan"),q("\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 Me(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 yi=e=>e.charAt(0).toUpperCase()+e.slice(1),j=e=>e.replace(/-([a-z])/g,(i,t)=>t.toUpperCase()),z=e=>yi(j(e));import Pi from"ora";var S=Pi();import Si from"degit";var He=async e=>{let i=O("Downloading template...");try{await Si("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 vi 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 Ue=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 ie(vi.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();import L from"node:path";I();import{exec as Ci}from"node:child_process";import{promisify as wi}from"node:util";var Ti=wi(Ci),Xe=async(e,i)=>{let t=L.join(e,a.HTTP_UTILS,"index.ts");if(l(t)){let r=await m(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';
|
|
3
|
-
`),
|
|
4
|
-
`),await
|
|
5
|
-
`,await
|
|
6
|
-
`),
|
|
7
|
-
`),await
|
|
8
|
-
`,await
|
|
2
|
+
var ai=Object.defineProperty;var Ce=(e,t)=>()=>(e&&(t=e(e=0)),t);var Xe=(e,t)=>{for(var i in t)ai(e,i,{get:t[i],enumerable:!0})};import q from"node:fs/promises";import We from"node:path";import{existsSync as Te}from"node:fs";var d,u,b,C,S,re,l,T=Ce(()=>{"use strict";d=async e=>q.readFile(e,"utf-8"),u=async(e,t)=>{await q.mkdir(We.dirname(e),{recursive:!0}),await q.writeFile(e,t,"utf-8")},b=async(e,t)=>{await q.mkdir(We.dirname(t),{recursive:!0}),await q.copyFile(e,t)},C=async e=>{Te(e)&&await q.unlink(e)},S=async e=>{Te(e)&&await q.rm(e,{recursive:!0,force:!0})},re=async(e,t)=>{let i=await d(e),r=JSON.parse(i),s=t(r);await u(e,JSON.stringify(s,null,2))},l=e=>Te(e)});var Ze={};Xe(Ze,{PROJECT_PATHS:()=>a});var a,N=Ce(()=>{"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"}});var et={};Xe(et,{cleanupHttpTypes:()=>ie,isFileUsed:()=>Ri,isStringUsed:()=>Ni,migrateClientUsages:()=>$e,removeHttpExports:()=>_e,updateConfigIndex:()=>Oe,updateHttpIndex:()=>Re,updateTypesIndex:()=>Ae,updateUtilsIndex:()=>Ne});import A from"node:path";import{exec as Ei}from"node:child_process";import{promisify as Ii}from"node:util";var Ie,Re,Ne,Ae,Oe,ie,$e,_e,Ri,Ni,fe=Ce(()=>{"use strict";T();N();Ie=Ii(Ei),Re=async(e,t)=>{let i=A.join(e,a.HTTP_UTILS,"index.ts");if(l(i)){let r=await d(i);r=r.replace(/export .* from '\.\/axios-client';?\n?/g,""),r=r.replace(/export .* from '\.\/fetch-client';?\n?/g,""),t.includes("fetch")&&!r.includes("fetch-client")&&(r+=`export * from './fetch-client';
|
|
3
|
+
`),t.includes("axios")&&!r.includes("axios-client")&&(r+=`export * from './axios-client';
|
|
4
|
+
`),await u(i,r)}},Ne=async e=>{let t=A.join(e,a.UTILS_INDEX);if(l(t)){let i=await d(t);i.includes("./http")||(i+=`export * from './http';
|
|
5
|
+
`,await u(t,i))}},Ae=async e=>{let t=A.join(e,a.TYPES_INDEX);if(l(t)){let i=await d(t);i.includes("./common")||(i+=`export * from './common';
|
|
6
|
+
`),i.includes("./utility")||(i+=`export * from './utility';
|
|
7
|
+
`),await u(t,i)}},Oe=async e=>{let t=A.join(e,a.CONFIG_INDEX);if(l(t)){let i=await d(t);i.includes("./app-apis")||(i+=`export * from './app-apis';
|
|
8
|
+
`,await u(t,i))}},ie=async(e,t)=>{let i=A.join(e,a.HTTP_TYPES);if(l(i)){let r=await d(i);t.includes("axios")||(r=r.replace(/declare module 'axios'\s*\{\s*export interface AxiosRequestConfig\s*\{[\s\S]*?\}\s*\}/g,""),r=r.replace(/\n\s*\n/g,`
|
|
9
9
|
|
|
10
10
|
`).trim()+`
|
|
11
|
-
`,await
|
|
12
|
-
`).filter(
|
|
13
|
-
`)
|
|
14
|
-
${t.join(`
|
|
11
|
+
`,await u(i,r))}},$e=async(e,t,i)=>{if(t===i)return;let r=t==="fetch"?"fetchClient":"axiosClient",s=i==="fetch"?"fetchClient":"axiosClient",o=t==="fetch"?"fetch-client":"axios-client",n=i==="fetch"?"fetch-client":"axios-client",c=A.join(e,"src");try{let p=`grep -rl "${r}" "${c}" --include="*.ts" --include="*.tsx" || true`,{stdout:m}=await Ie(p);if(!m.trim())return;let h=m.trim().split(`
|
|
12
|
+
`).filter(y=>y);for(let y of h){if(!l(y))continue;let x=await d(y),w=!1,D=new RegExp(`(import\\s*\\{[^}]*?)\\b${r}\\b([^}]*?\\}\\s*from\\s*['"][^'"]*?/http['"])`,"g");D.test(x)&&(x=x.replace(D,`$1${s}$2`),w=!0);let I=new RegExp(`import\\s+${r}\\s+from\\s+['"]([^'"]*?)/${o}['"]`,"g");I.test(x)&&(x=x.replace(I,`import ${s} from '$1/${n}'`),w=!0);let F=new RegExp(`\\b${r}\\b(?=\\.)`,"g");F.test(x)&&(x=x.replace(F,s),w=!0);let te=new RegExp(`\\b${r}\\b(?![.\\w])`,"g");te.test(x)&&(x=x.replace(te,s),w=!0),w&&await u(y,x)}}catch(p){console.warn("Warning: Could not scan for HTTP client usages:",p)}},_e=async e=>{let t=A.join(e,a.UTILS_INDEX);if(l(t)){let r=await d(t);r=r.replace(/^\s*export\s+\*\s+from\s+['"]\.\/http['"];?.*$/gm,""),await u(t,r)}let i=A.join(e,a.TYPES_INDEX);if(l(i)){let r=await d(i),s=A.join(e,a.COMMON_TYPES_DIR);if(!l(s))r=r.replace(/^\s*export\s+\*\s+from\s+['"]\.\/common['"];?.*$/gm,"");else{let o=A.join(s,"index.ts");if(l(o)){let n=await d(o);n=n.replace(/^\s*export\s+\*\s+from\s+['"]\.\/http\.types['"];?.*$/gm,""),await u(o,n)}}l(A.join(e,a.UTILITY_TYPES_DIR))||(r=r.replace(/^\s*export\s+\*\s+from\s+['"]\.\/utility['"];?.*$/gm,"")),await u(i,r)}},Ri=async(e,t,i=[])=>{let r=A.join(e,"src"),o=`grep -r "from ['\\"].*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}.*['\\"]" "${r}" --include="*.ts" --include="*.tsx" || true`;try{let{stdout:n}=await Ie(o);return n.trim()?n.trim().split(`
|
|
13
|
+
`).filter(m=>{let[h]=m.split(":"),y=A.resolve(e,h);return!i.some(x=>!!(y===x||y.startsWith(x+A.sep)))}).length>0:!1}catch(n){return console.warn(`Warning: Failed to check usage for ${t}:`,n),!0}},Ni=async(e,t,i=[])=>{let r=A.join(e,"src"),o=`grep -r "${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}" "${r}" --include="*.ts" --include="*.tsx" || true`;try{let{stdout:n}=await Ie(o);return n.trim()?n.trim().split(`
|
|
14
|
+
`).filter(m=>{let[h]=m.split(":"),y=A.resolve(e,h);return!i.some(x=>!!(y===x||y.startsWith(x+A.sep)))}).length>0:!1}catch(n){return console.warn(`Warning: Failed to check usage for string ${t}:`,n),!0}}});import{Command as Mo}from"commander";import Fe from"node:path";import V from"picocolors";import ci from"ora";function $(e="",t){let i=ci({text:e,...t});return i.start(),i}import li from"enquirer";var{prompt:pi}=li,Je=async e=>{let t=await pi([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:i=>/^[a-z0-9-_]+$/.test(i)?!0:"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:i=>/^\d+\.\d+\.\d+$/.test(i)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:i=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(i)?!0:"Please enter a valid email address."},{type:"select",name:"packageManager",message:"Which package manager would you like to use?",choices:["npm","yarn","pnpm","bun"],initial:1},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",validate:i=>{if(!i)return!0;let r=/^https:\/\/github\.com\/[\w-]+\/[\w.-]+$/,s=/^git@github\.com:[\w-]+\/[\w.-]+\.git$/;return!r.test(i)&&!s.test(i)?"Please enter a valid GitHub repository URL (e.g., https://github.com/user/repo)":!0}},{type:"confirm",name:"keepTemplates",message:"Do you want to keep GitHub issue and pull request templates?",initial:!1},{type:"select",name:"httpClient",message:"Which HTTP client do you want to use?",choices:["axios","fetch","both","none"],initial:1},{type:"confirm",name:"reactSecureStorage",message:"Do you want to include react-secure-storage?",initial:!0,skip:function(){let i=this.state?.answers??this.enquirer?.answers??{};return!!(i.httpClient&&i.httpClient!=="none")}},{type:"confirm",name:"darkMode",message:"Do you want to include Dark Mode (Tailwind + next-themes)?",initial:!0},{type:"confirm",name:"redux",message:"Do you want to include Redux Toolkit?",initial:!0},{type:"confirm",name:"i18n",message:"Do you want to include Internationalization (next-intl)?",initial:!0},{type:"multiselect",name:"communityFiles",message:"Select community files to include:",choices:[{name:"CODE_OF_CONDUCT.md",value:"CODE_OF_CONDUCT.md"},{name:"CONTRIBUTING.md",value:"CONTRIBUTING.md"},{name:"SECURITY.md",value:"SECURITY.md"}],initial:[]},{type:"confirm",name:"readme",message:"Do you want to create a README.md?",initial:!0},{type:"confirm",name:"docker",message:"Do you want to include Docker configuration?",initial:!1},{type:"input",name:"containerName",message:"Docker Container Name:",initial:"next-app",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:i=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(i)?!0:"Invalid Docker container name."},{type:"input",name:"imageName",message:"Docker Image Name:",initial:"nextjs-starter",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:i=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(i)?!0:"Invalid Docker image name (must be lowercase)."},{type:"input",name:"imageTag",message:"Docker Image Tag:",initial:"latest",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:i=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(i)?!0:"Invalid Docker image tag."},{type:"confirm",name:"ci",message:"Do you want to include GitHub Actions (CI/CD)?",initial:!1},{type:"confirm",name:"preCommitHooks",message:"Do you want to setup pre-commit hooks (Husky, Commitlint, Lint-staged)?",initial:!0},{type:"confirm",name:"commitizen",message:"Do you want to setup Commitizen?",initial:!0},{type:"confirm",name:"copyEnv",message:"Want to copy .env.example to .env?",initial:!0}]);if(t.company=t.author,t.gitRemote&&!t.gitHomepage){let i=t.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");t.gitHomepage=`${i}#readme`,t.gitIssues=`${i}/issues`}return t};T();import{exec as mi}from"node:child_process";import{promisify as di}from"node:util";var me=di(mi),ze=async(e,t)=>{try{await me("git init",{cwd:e}),await me("git add .",{cwd:e}),await me('git commit -m "Initial commit from @teispace/next-maker"',{cwd:e}),t&&await me(`git remote add origin ${t}`,{cwd:e})}catch(i){console.warn("Failed to initialize git repository",i)}};import{exec as ui}from"node:child_process";import{promisify as fi}from"node:util";var de=fi(ui),Ve=async(e,t)=>{let i=`${t} install`;try{await de(i,{cwd:e})}catch(r){throw new Error(`Failed to install dependencies with ${t}: ${r}`)}},H=async(e,t,i)=>{let r=t==="npm"?`${t} run ${i}`:`${t} ${i}`;try{await de(r,{cwd:e})}catch(s){console.warn(`Warning: Failed to run script '${i}': ${s}`)}},gi=()=>{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:t}=await import("node:fs"),i=await import("node:path");return t(i.join(e,"pnpm-lock.yaml"))?"pnpm":t(i.join(e,"yarn.lock"))?"yarn":t(i.join(e,"bun.lockb"))?"bun":t(i.join(e,"package-lock.json"))?"npm":gi()},xi=async(e,t,i)=>{if(i.length===0)return;let s=`${hi(t)} ${i.join(" ")}`;try{await de(s,{cwd:e})}catch(o){throw new Error(`Failed to install packages with ${t}: ${o}`)}},hi=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"}},M=async(e,t)=>{let i=await G(e);await xi(e,i,[t])},yi=async(e,t,i)=>{if(i.length===0)return;let s=`${Si(t)} ${i.join(" ")}`;try{await de(s,{cwd:e})}catch(o){throw new Error(`Failed to uninstall packages with ${t}: ${o}`)}},Si=e=>{switch(e){case"npm":return"npm uninstall";case"yarn":return"yarn remove";case"pnpm":return"pnpm remove";case"bun":return"bun remove";default:return"npm uninstall"}},Ee=async(e,t)=>{let i=await G(e);await yi(e,i,[t])};import U from"picocolors";var Pi={reset:e=>e,red:U.red,green:U.green,yellow:U.yellow,blue:U.blue,cyan:U.cyan,magenta:U.magenta,white:U.white,gray:U.gray,bright:U.bold,dim:U.dim};function Z(e,t="reset"){let i=Pi[t]??(r=>r);console.log(i(e))}function ue(e){Z(`\u2716 ${e}`,"red")}var R=ue;function f(e){Z(e)}function Ke(){console.log(""),Z("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557","cyan"),Z("\u2551 \u2551","cyan"),Z("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),Z("\u2551 \u2551","cyan"),Z("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D","cyan"),console.log("")}function Be(e){let{logger:t=n=>console.error(n),exitOnCancel:i=process.env.NODE_ENV!=="test"}=e??{},r=()=>{console.log(""),console.log(""),t("Setup cancelled by user"),console.log(""),i&&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){t(`Uncaught exception: ${n.message}`);return}t(`Uncaught exception: ${String(n)}`)},o=n=>{if(n instanceof Error){t(`Unhandled promise rejection: ${n.message}`);return}t(`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 vi=e=>e.charAt(0).toUpperCase()+e.slice(1),L=e=>e.replace(/-([a-z])/g,(t,i)=>i.toUpperCase()),z=e=>vi(L(e));import wi from"ora";var v=wi();import Ci from"degit";var qe=async e=>{let t=$("Downloading template...");try{await Ci("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(e),t.succeed("Template downloaded successfully.")}catch(i){throw t.fail("Failed to download template."),i}};T();import Ti from"node:path";N();var _={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 Qe=async(e,t)=>{let i=$("Configuring package.json...");try{let r=t.gitRemote,s=t.gitHomepage,o=t.gitIssues;t.gitRemote&&(t.gitRemote.startsWith("git@github.com:")&&(r=t.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(Ti.join(e,a.PACKAGE_JSON),n=>(n.name=t.projectName,n.version=t.version,n.description=t.description,n.author=t.author,delete n.packageManager,t.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),t.redux||(delete n.dependencies[_.REDUX_TOOLKIT],delete n.dependencies[_.REACT_REDUX],delete n.dependencies[_.REDUX_PERSIST]),t.httpClient!=="none"||t.reactSecureStorage||delete n.dependencies[_.REACT_SECURE_STORAGE],t.i18n||delete n.dependencies[_.NEXT_INTL],t.darkMode||delete n.dependencies[_.NEXT_THEMES],t.httpClient==="none"?delete n.dependencies[_.AXIOS]:t.httpClient==="fetch"&&delete n.dependencies[_.AXIOS],n)),i.succeed("package.json configured.")}catch(r){throw i.fail("Failed to configure package.json."),r}};T();import g from"node:path";N();fe();var tt=async(e,t)=>{let i=$("Customizing features...");try{await Ai(e,t),await Oi(e,t),await $i(e,t),await _i(e,t),await bi(e,t),await Fi(e),await ji(e),await ki(e),i.succeed("Features customized.")}catch(r){throw i.fail("Failed to customize features."),r}},Ai=async(e,t)=>{let i=g.join(e,a.HTTP_UTILS),r=t.httpClient!=="none"||t.reactSecureStorage;if(t.httpClient==="none"){if(await S(g.join(e,a.AXIOS_CLIENT)),await S(g.join(e,a.FETCH_CLIENT)),r)await u(g.join(i,"index.ts"),`export * from './token-store';
|
|
15
|
+
`),await C(g.join(e,a.CLIENT_UTILS)),await ie(e,[]);else{await S(i);let o=g.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 C(g.join(e,a.APP_APIS));let n=g.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=g.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 S(g.join(e,a.ERRORS_DIR)),!r){await S(g.join(e,a.COMMON_TYPES_DIR)),await S(g.join(e,a.UTILITY_TYPES_DIR));let o=g.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(t.httpClient==="axios"){await S(g.join(e,a.FETCH_CLIENT));let s=await d(g.join(i,"index.ts"));s=s.replace(/export .* from '\.\/fetch-client';\n/g,""),await u(g.join(i,"index.ts"),s);let o=g.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(t.httpClient==="fetch"){await S(g.join(e,a.AXIOS_CLIENT));let s=await d(g.join(i,"index.ts"));s=s.replace(/export .* from '\.\/axios-client';\n/g,""),await u(g.join(i,"index.ts"),s),await ie(e,["fetch"]);let o=g.join(e,a.HTTP_TYPES);if(l(o)){let n=await d(o);n=n.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await u(o,n)}}},Oi=async(e,t)=>{t.httpClient!=="none"||t.reactSecureStorage||await S(g.join(e,a.STORAGE_SERVICE))},$i=async(e,t)=>{if(!t.redux){await S(g.join(e,a.STORE)),await S(g.join(e,a.COUNTER_FEATURE)),await C(g.join(e,a.STORE_PROVIDER));let i=g.join(e,a.PROVIDERS_INDEX),r=await d(i);r=r.replace(/export \* from '\.\/StoreProvider';\n/,""),await u(i,r);let s=[g.join(e,a.ROOT_PAGE),g.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)}}},_i=async(e,t)=>{if(!t.darkMode){await C(g.join(e,a.THEME_PROVIDER));let i=g.join(e,a.PROVIDERS_INDEX),r=await d(i);r=r.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await u(i,r);let s=g.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(!t.i18n){let o=g.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)}}}},bi=async(e,t)=>{if(!t.i18n){await S(g.join(e,a.I18N_DIR)),await S(g.join(e,a.LOCALE_DIR)),await C(g.join(e,a.PROXY)),await C(g.join(e,a.MIDDLEWARE)),await C(g.join(e,a.I18N_TYPES)),await C(g.join(e,a.APP_LOCALES));let i=g.join(e,a.TYPES_INDEX);if(l(i)){let n=await d(i);n=n.replace(/export \* from '\.\/i18n';\n/,""),await u(i,n)}let r=g.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=g.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=g.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)}}},Fi=async e=>{await C(g.join(e,a.LICENSE))},ji=async e=>{await C(g.join(e,a.CHANGELOG))},ki=async e=>{await C(g.join(e,a.NVM_RC)),await C(g.join(e,a.NPM_RC))};T();N();import be from"node:path";var it=async(e,t)=>{let i=[],r=[];t.redux&&(i.push("import { StoreProvider } from '@/providers';"),r.push("StoreProvider")),t.darkMode&&(i.push("import { CustomThemeProvider } from '@/providers';"),r.push("CustomThemeProvider")),t.i18n&&(i.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),i.push("import { SupportedLocale } from '@/types/i18n';"));let s=`'use client';
|
|
16
|
+
${i.join(`
|
|
15
17
|
`)}
|
|
16
18
|
|
|
17
19
|
export const RootProvider = ({
|
|
18
20
|
children,
|
|
19
|
-
${
|
|
21
|
+
${t.i18n?`locale,
|
|
20
22
|
messages,`:""}
|
|
21
23
|
}: {
|
|
22
24
|
children: React.ReactNode;
|
|
23
|
-
${
|
|
25
|
+
${t.i18n?`locale: SupportedLocale;
|
|
24
26
|
messages: AbstractIntlMessages;`:""}
|
|
25
27
|
}) => {
|
|
26
28
|
return (
|
|
27
|
-
`,o="{children}";
|
|
29
|
+
`,o="{children}";t.i18n&&(o=`<NextIntlClientProvider locale={locale} messages={messages}>
|
|
28
30
|
${o}
|
|
29
|
-
</NextIntlClientProvider>`),
|
|
31
|
+
</NextIntlClientProvider>`),t.darkMode&&(o=`<CustomThemeProvider>
|
|
30
32
|
${o}
|
|
31
|
-
</CustomThemeProvider>`),
|
|
33
|
+
</CustomThemeProvider>`),t.redux&&(o=`<StoreProvider>
|
|
32
34
|
${o}
|
|
33
35
|
</StoreProvider>`),o==="{children}"&&(o="<>{children}</>"),s+=` ${o}
|
|
34
36
|
);
|
|
35
37
|
};
|
|
36
|
-
`,await
|
|
38
|
+
`,await u(be.join(e,a.ROOT_PROVIDER),s)},ot=async(e,t)=>{if(!t.i18n){let i=`import type { Metadata } from 'next';
|
|
37
39
|
import '@/styles/globals.css';
|
|
38
40
|
import { Livvic } from 'next/font/google';
|
|
39
41
|
import { RootProvider } from '@/providers';
|
|
@@ -46,8 +48,8 @@ const livvic = Livvic({
|
|
|
46
48
|
});
|
|
47
49
|
|
|
48
50
|
export const metadata: Metadata = {
|
|
49
|
-
title: '${
|
|
50
|
-
description: '${
|
|
51
|
+
title: '${t.projectName}',
|
|
52
|
+
description: '${t.description}',
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
export default function RootLayout({
|
|
@@ -56,8 +58,8 @@ export default function RootLayout({
|
|
|
56
58
|
children: React.ReactNode;
|
|
57
59
|
}>) {
|
|
58
60
|
return (
|
|
59
|
-
<html lang="en" suppressHydrationWarning={${
|
|
60
|
-
<body className={\`\${livvic.variable} ${
|
|
61
|
+
<html lang="en" suppressHydrationWarning={${t.darkMode?"true":"false"}}>
|
|
62
|
+
<body className={\`\${livvic.variable} ${t.darkMode?"bg-light dark:bg-dark ":""}antialiased\`}>
|
|
61
63
|
<RootProvider>
|
|
62
64
|
{children}
|
|
63
65
|
</RootProvider>
|
|
@@ -65,34 +67,34 @@ export default function RootLayout({
|
|
|
65
67
|
</html>
|
|
66
68
|
);
|
|
67
69
|
}
|
|
68
|
-
`;await
|
|
70
|
+
`;await u(be.join(e,a.ROOT_LAYOUT),i);let r=t.redux?`import { Counter } from '@/features/counter';
|
|
69
71
|
|
|
70
|
-
`:"",s=
|
|
72
|
+
`:"",s=t.redux?`
|
|
71
73
|
<Counter />`:"",o=`${r}export default function Home() {
|
|
72
74
|
return (
|
|
73
75
|
<div className="flex min-h-screen flex-col items-center justify-center p-24">
|
|
74
|
-
<h1 className="text-4xl font-bold">Welcome to ${
|
|
76
|
+
<h1 className="text-4xl font-bold">Welcome to ${t.projectName}</h1>
|
|
75
77
|
<p className="mt-4 text-xl">Get started by editing src/app/page.tsx</p>${s}
|
|
76
78
|
</div>
|
|
77
79
|
);
|
|
78
80
|
}
|
|
79
|
-
`;await
|
|
80
|
-
`};s("CONTAINER_NAME",
|
|
81
|
+
`;await u(be.join(e,a.ROOT_PAGE),o)}};T();N();import E from"node:path";import{readdir as rt}from"node:fs/promises";var nt=async(e,t)=>{await Di(e,t),await Li(e,t),await Mi(e,t),await Hi(e,t),await Gi(e,t),await Ui(e,t),await Yi(e,t)},Di=async(e,t)=>{t.preCommitHooks||(await S(E.join(e,a.HUSKY_DIR)),await C(E.join(e,a.COMMITLINT_CONFIG)),await C(E.join(e,a.LINTSTAGED_RC)),await re(E.join(e,a.PACKAGE_JSON),i=>(delete i.devDependencies[_.HUSKY],delete i.devDependencies[_.COMMITLINT_CLI],delete i.devDependencies[_.COMMITLINT_CONFIG],delete i.devDependencies[_.LINT_STAGED],delete i.scripts.prepare,delete i.scripts.postinstall,delete i.commitlint,delete i["lint-staged"],i)))},Li=async(e,t)=>{t.commitizen||(await C(E.join(e,a.CZRC)),await re(E.join(e,a.PACKAGE_JSON),i=>(delete i.devDependencies[_.COMMITIZEN],delete i.devDependencies[_.CZ_CONVENTIONAL_CHANGELOG],delete i.config?.commitizen,i.config&&Object.keys(i.config).length===0&&delete i.config,delete i.scripts.commit,i)))},Mi=async(e,t)=>{t.ci||await S(E.join(e,a.GITHUB_WORKFLOWS))},Hi=async(e,t)=>{let i=E.join(e,a.GITHUB_DIR);if(!t.keepTemplates)await S(E.join(i,a.GITHUB_ISSUE_TEMPLATE)),await C(E.join(i,a.GITHUB_PR_TEMPLATE));else{let r=E.join(i,a.GITHUB_ISSUE_TEMPLATE),s=E.join(i,a.GITHUB_PR_TEMPLATE),o=n=>n.replace(/Teispace/g,t.company).replace(/support@teispace\.com/g,t.email).replace(/Next\.js Starter/g,t.projectName).replace(/\[AUTHOR\]/g,t.author).replace(/\[COMPANY\]/g,t.company).replace(/\[EMAIL\]/g,t.email);if(l(s)){let n=await d(s);n=o(n),await u(s,n)}try{if(l(r)){let n=await rt(r);for(let c of n){let p=E.join(r,c),m=await d(p);m=o(m),await u(p,m)}}}catch{}}},Gi=async(e,t)=>{let i=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let r of i)t.communityFiles.includes(r)||await C(E.join(e,r))},Ui=async(e,t)=>{if(t.docker){let i=E.join(e,a.ENV_EXAMPLE);if(l(i)){let r=await d(i),s=(o,n)=>{let c=new RegExp(`${o}=.*`);c.test(r)?r=r.replace(c,`${o}=${n}`):r+=`${o}=${n}
|
|
82
|
+
`};s("CONTAINER_NAME",t.containerName||"next-app"),s("IMAGE_NAME",t.imageName||"nextjs-starter"),s("IMAGE_TAG",t.imageTag||"latest"),await u(i,r)}}else{await C(E.join(e,a.DOCKERFILE)),await C(E.join(e,a.DOCKER_COMPOSE)),await C(E.join(e,a.DOCKERIGNORE));let i=E.join(e,a.ENV_EXAMPLE);if(l(i)){let r=await d(i);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(i,r)}}},Yi=async(e,t)=>{let i=async o=>{let n=await rt(o,{withFileTypes:!0}),c=[];for(let p of n){let m=E.join(o,p.name);p.isDirectory()&&p.name!=="node_modules"&&p.name!==".git"?c.push(...await i(m)):p.isFile()&&p.name.toLowerCase()==="readme.md"&&c.push(m)}return c},r=await i(e),s=E.join(e,a.README);for(let o of r)o!==s&&await C(o);if(t.readme){let o=`# ${t.projectName}
|
|
81
83
|
|
|
82
|
-
${
|
|
84
|
+
${t.description}
|
|
83
85
|
|
|
84
86
|
## Getting Started
|
|
85
87
|
|
|
86
88
|
First, run the development server:
|
|
87
89
|
|
|
88
90
|
\`\`\`bash
|
|
89
|
-
${
|
|
91
|
+
${t.packageManager==="npm"?"npm run dev":t.packageManager+" dev"}
|
|
90
92
|
\`\`\`
|
|
91
93
|
|
|
92
94
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
93
|
-
`;await
|
|
94
|
-
Cleaning up: Deleting directory ${
|
|
95
|
-
Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await
|
|
95
|
+
`;await u(s,o)}else await C(s)};var st=e=>{e.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async t=>{await Xi(t)})},Xi=async e=>{Ke(),f("Welcome to the Teispace Next.js App Creator!"),f("");let t=await Je(e),i=Fe.resolve(process.cwd(),t.projectName);l(i)&&(console.error(V.red(`Error: Directory ${t.projectName} already exists.`)),process.exit(1));let r=$("Initializing project..."),s=async()=>{if(l(i)){r.stop(),console.log(V.yellow(`
|
|
96
|
+
Cleaning up: Deleting directory ${t.projectName}...`));try{await S(i),console.log(V.green("Cleanup successful."))}catch(n){console.error(V.red(`Failed to clean up directory ${t.projectName}:`),n)}}},o=async()=>{console.log(V.red(`
|
|
97
|
+
Process interrupted. Cleaning up...`)),await s(),process.exit(1)};process.on("SIGINT",o),process.on("SIGTERM",o);try{if(await qe(i),await Qe(i,t),await tt(i,t),r.text="Generating code...",await it(i,t),await ot(i,t),r.text="Setting up developer tools...",await nt(i,t),r.text="Initializing Git...",await ze(i,t.gitRemote),r.text="Installing dependencies...",await Ve(i,t.packageManager),r.text="Formatting and Linting...",await H(i,t.packageManager,"format"),await H(i,t.packageManager,"lint:fix"),t.copyEnv){r.text="Creating .env file...";let n=Fe.join(i,".env.example"),c=Fe.join(i,".env");l(n)&&await(await import("node:fs/promises")).copyFile(n,c)}process.off("SIGINT",o),process.off("SIGTERM",o),r.succeed(V.green(`Project ${t.projectName} created successfully!`)),f(""),f("To get started:"),f(V.cyan(` cd ${t.projectName}`)),f(V.cyan(` ${t.packageManager==="npm"?"npm run dev":t.packageManager+" dev"}`)),f("")}catch(n){r.fail("Failed to create project."),console.error(n),await s(),process.exit(1)}};import O from"picocolors";import De from"node:path";import Ji from"enquirer";var{prompt:Wi}=Ji,at=async(e,t,i,r,s,o,n)=>{let c=[];e||c.push({type:"input",name:"featureName",message:"What is the feature name?",initial:"my-feature",validate:m=>/^[a-z0-9-]+$/.test(m)?!0:"Feature name must be lowercase and contain only alphanumeric characters and hyphens."}),t&&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}})),i&&i!=="none"&&o===void 0&&n===void 0&&(c.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),i==="both"&&c.push({type:"select",name:"selectedHttpClient",message:"Which HTTP client to use for the service?",choices:["fetch","axios"],initial:0,skip(){return!this.state.answers.createService}}));let p=c.length>0?await Wi(c):{};return{featureName:e||p.featureName,hasRedux:t||!1,createStore:r===!0?!1:s!==void 0?!0:p.createStore||!1,persistStore:s==="persist"?!0:s==="no-persist"?!1:p.persistStore||!1,httpClient:i||"none",createService:o===!0?!1:n!==void 0?!0:p.createService||!1,selectedHttpClient:n||p.selectedHttpClient||(i==="both"?"fetch":i!=="none"?i:void 0)}};import{readFile as zi,access as je}from"node:fs/promises";import ne from"node:path";var oe=async e=>{let t=!1,i=!1,r=!1,s=!1;try{let o=ne.join(e,"package.json"),n=await zi(o,"utf-8"),c=JSON.parse(n),p={...c.dependencies,...c.devDependencies};t=!!(p["@reduxjs/toolkit"]&&p["react-redux"]),i=!!p.axios,s=!!p["next-intl"];let m=ne.join(e,"src","lib","utils","http","axios-client");try{await je(m),i=i&&!0}catch{i=!1}let h=ne.join(e,"src","lib","utils","http","fetch-client");try{await je(h),r=!0}catch{r=!1}let y;return i&&r?y="both":i?y="axios":r?y="fetch":y="none",{hasRedux:t,httpClient:y,hasI18n:s}}catch(o){throw new Error(`Failed to detect project setup: ${o}`)}},ct=async(e,t,i=ne.join("src","features"))=>{let r=ne.join(e,i,t);try{return await je(r),!0}catch{return!1}};import{writeFile as Y,mkdir as se}from"node:fs/promises";import j from"node:path";var lt=async e=>{let{featurePath:t}=e;await se(j.join(t,"components"),{recursive:!0}),await se(j.join(t,"hooks"),{recursive:!0}),await se(j.join(t,"types"),{recursive:!0}),e.createStore&&await se(j.join(t,"store"),{recursive:!0}),e.createService&&await se(j.join(t,"services"),{recursive:!0}),await Vi(e),await Ki(e),await Bi(e),await Qi(e),e.createStore&&await qi(e),e.createService&&e.httpClient&&await Zi(e)};var Vi=async e=>{let{featureName:t,featurePath:i}=e,r=z(t),s=`use${r}`,o=`'use client';
|
|
96
98
|
import { ${s} } from '../hooks/${s}';
|
|
97
99
|
|
|
98
100
|
export function ${r}() {
|
|
@@ -107,9 +109,9 @@ export function ${r}() {
|
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
export default ${r};
|
|
110
|
-
`;await
|
|
112
|
+
`;await Y(j.join(i,"components",`${r}.tsx`),o)},Ki=async e=>{let{featureName:t,featurePath:i,createStore:r}=e,s=z(t),o=`use${s}`,n;r?n=`'use client';
|
|
111
113
|
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
|
112
|
-
import { select${s}State, setLoading, setError } from '../store/${
|
|
114
|
+
import { select${s}State, setLoading, setError } from '../store/${t}.selectors';
|
|
113
115
|
|
|
114
116
|
export const ${o} = () => {
|
|
115
117
|
const dispatch = useAppDispatch();
|
|
@@ -143,13 +145,13 @@ export const ${o} = () => {
|
|
|
143
145
|
// Add your methods here
|
|
144
146
|
} as const;
|
|
145
147
|
};
|
|
146
|
-
`,await
|
|
148
|
+
`,await Y(j.join(i,"hooks",`${o}.ts`),n)},Bi=async e=>{let{featureName:t,featurePath:i,createStore:r}=e,n=`export interface ${`${z(t)}State`} {
|
|
147
149
|
// Add your state properties here
|
|
148
150
|
${r?`loading: boolean;
|
|
149
151
|
error: string | null;`:"// example: value: string;"}
|
|
150
152
|
}
|
|
151
|
-
`;await
|
|
152
|
-
import { ${s}State } from '../types/${
|
|
153
|
+
`;await Y(j.join(i,"types",`${t}.types.ts`),n)},qi=async e=>{let{featureName:t,featurePath:i,persistStore:r}=e,s=z(t),o=L(t),n=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
154
|
+
import { ${s}State } from '../types/${t}.types';
|
|
153
155
|
|
|
154
156
|
const initialState: ${s}State = {
|
|
155
157
|
loading: false,
|
|
@@ -177,23 +179,23 @@ export const ${o}Slice = createSlice({
|
|
|
177
179
|
export const { setLoading, setError, resetState } = ${o}Slice.actions;
|
|
178
180
|
|
|
179
181
|
export const ${o}Reducer = ${o}Slice.reducer;
|
|
180
|
-
`;await
|
|
182
|
+
`;await Y(j.join(i,"store",`${t}.slice.ts`),n);let c=`import { RootState } from '@/store/rootReducer';
|
|
181
183
|
|
|
182
184
|
export const select${s}State = (state: RootState) => state.${o};
|
|
183
|
-
export { setLoading, setError, resetState } from './${
|
|
184
|
-
`;if(await
|
|
185
|
+
export { setLoading, setError, resetState } from './${t}.slice';
|
|
186
|
+
`;if(await Y(j.join(i,"store",`${t}.selectors.ts`),c),r){let m=`import { PersistConfig } from 'redux-persist';
|
|
185
187
|
import storage from 'redux-persist/lib/storage';
|
|
186
|
-
import { ${s}State } from '../types/${
|
|
188
|
+
import { ${s}State } from '../types/${t}.types';
|
|
187
189
|
|
|
188
190
|
export const ${o}PersistConfig: PersistConfig<${s}State> = {
|
|
189
191
|
key: '${o}',
|
|
190
192
|
storage,
|
|
191
193
|
// whitelist: ['someField'], // Specify which fields to persist
|
|
192
194
|
};
|
|
193
|
-
`;await
|
|
194
|
-
export * from './${
|
|
195
|
+
`;await Y(j.join(i,"store","persist.ts"),m)}let p=`export * from './${t}.slice';
|
|
196
|
+
export * from './${t}.selectors';${r?`
|
|
195
197
|
export * from './persist';`:""}
|
|
196
|
-
`;await
|
|
198
|
+
`;await Y(j.join(i,"store","index.ts"),p)},Zi=async e=>{let{featureName:t,featurePath:i,httpClient:r}=e,s=L(t),o;r==="axios"?o=`import { AppApis } from '@/lib/config';
|
|
197
199
|
import { axiosClient } from '@/lib/utils/http';
|
|
198
200
|
import { ResultAsync } from '@/types';
|
|
199
201
|
|
|
@@ -211,43 +213,43 @@ export const ${s}Service = {
|
|
|
211
213
|
return fetchClient.get<string>(AppApis.${s}.getAll);
|
|
212
214
|
},
|
|
213
215
|
};
|
|
214
|
-
`,await
|
|
216
|
+
`,await Y(j.join(i,"services",`${t}.service.ts`),o)},Qi=async e=>{let{featureName:t,featurePath:i,createStore:r,createService:s}=e,o=z(t),n=`export { default as ${o} } from './components/${o}';
|
|
215
217
|
export { use${o} } from './hooks/use${o}';
|
|
216
|
-
export * from './types/${
|
|
218
|
+
export * from './types/${t}.types';${r?`
|
|
217
219
|
export * from './store';`:""}${s?`
|
|
218
|
-
export * from './services/${
|
|
219
|
-
`;await
|
|
220
|
-
`+o.slice(
|
|
221
|
-
`+o;let
|
|
220
|
+
export * from './services/${t}.service';`:""}
|
|
221
|
+
`;await Y(j.join(i,"index.ts"),n)};import{readFile as pt,writeFile as mt}from"node:fs/promises";import ke from"node:path";var dt=async(e,t,i,r=ke.join("src","features"))=>{let s=ke.join(e,"src","store","rootReducer.ts");try{let o=await pt(s,"utf-8"),n=L(t),c=`${n}Reducer`,p=i?`${n}PersistConfig`:"",m=r.replace(/^src\//,"@/"),h=i?`import { ${c}, ${p} } from '${m}/${t}/store';`:`import { ${c} } from '${m}/${t}/store';`,y=/import\s+.*\s+from\s+['"].*['"];?\n/g,x=o.match(y);if(x&&x.length>0){let I=x[x.length-1],F=o.lastIndexOf(I);o=o.slice(0,F+I.length)+h+`
|
|
222
|
+
`+o.slice(F+I.length)}else o=h+`
|
|
223
|
+
`+o;let w=/combineReducers\(\{([^}]*)\}\)/s,D=o.match(w);if(D){let I=D[1],F=i?`
|
|
222
224
|
${n}: persistReducer(${p}, ${c}),`:`
|
|
223
|
-
${n}: ${c},`,
|
|
224
|
-
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await
|
|
225
|
-
`+o.slice(
|
|
226
|
-
`+o;let
|
|
225
|
+
${n}: ${c},`,te=I.trimEnd()+F;o=o.replace(w,`combineReducers({${te}
|
|
226
|
+
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await mt(s,o)}catch(o){throw new Error(`Failed to register feature in rootReducer: ${o}`)}},ut=async(e,t,i,r)=>{let s=ke.join(e,"src","store","rootReducer.ts");try{let o=await pt(s,"utf-8"),n=L(t),c=`${n}Reducer`,p=i?`${n}PersistConfig`:"",m=r.replace(/^src\//,"@/"),h=i?`import { ${c}, ${p} } from '${m}/${t}';`:`import { ${c} } from '${m}/${t}';`,y=/import\s+.*\s+from\s+['"].*['"];?\n/g,x=o.match(y);if(x&&x.length>0){let I=x[x.length-1],F=o.lastIndexOf(I);o=o.slice(0,F+I.length)+h+`
|
|
227
|
+
`+o.slice(F+I.length)}else o=h+`
|
|
228
|
+
`+o;let w=/combineReducers\(\{([^}]*)\}\)/s,D=o.match(w);if(D){let I=D[1],F=i?`
|
|
227
229
|
${n}: persistReducer(${p}, ${c}),`:`
|
|
228
|
-
${n}: ${c},`,
|
|
229
|
-
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await
|
|
230
|
-
base: \`\${API_PREFIX}/${
|
|
231
|
-
getAll: \`\${API_PREFIX}/${
|
|
232
|
-
},`,p=/(\s*)\} as const;/;if(!o.match(p))throw new Error("Could not find closing brace of AppApis object");let
|
|
230
|
+
${n}: ${c},`,te=I.trimEnd()+F;o=o.replace(w,`combineReducers({${te}
|
|
231
|
+
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await mt(s,o)}catch(o){throw new Error(`Failed to register slice in rootReducer: ${o}`)}};import{readFile as eo,writeFile as to}from"node:fs/promises";import io from"node:path";var ge=async e=>{let{serviceName:t,projectPath:i}=e,r=L(t),s=io.join(i,"src","lib","config","app-apis.ts");try{let o=await eo(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}: {
|
|
232
|
+
base: \`\${API_PREFIX}/${t}\`,
|
|
233
|
+
getAll: \`\${API_PREFIX}/${t}\`,
|
|
234
|
+
},`,p=/(\s*)\} as const;/;if(!o.match(p))throw new Error("Could not find closing brace of AppApis object");let h=o.lastIndexOf("} as const;"),y=o.substring(0,h),x=o.substring(h),w=y.trim().endsWith(","),D=y.match(/:\s*\{[^}]*\},\s*$/),I;D||w?I=`${y}
|
|
233
235
|
${c}
|
|
234
|
-
${
|
|
236
|
+
${x}`:I=y.trimEnd()+`
|
|
235
237
|
`+c+`
|
|
236
|
-
`+
|
|
238
|
+
`+x,await to(s,I)}catch(o){throw new Error(`Failed to register API endpoints: ${o}`)}};var ft=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(t,i)=>{try{let r=process.cwd();i.store&&!["persist","no-persist"].includes(i.store)&&(R("Invalid --store option. Use: persist or no-persist"),process.exit(1)),i.service&&!["axios","fetch"].includes(i.service)&&(R("Invalid --service option. Use: axios or fetch"),process.exit(1)),i.skipStore&&i.store&&(R("Cannot use --skip-store and --store together"),process.exit(1)),i.skipService&&i.service&&(R("Cannot use --skip-service and --service together"),process.exit(1)),f(O.cyan(`
|
|
237
239
|
\u{1F3AF} Feature Generator
|
|
238
|
-
`)),
|
|
239
|
-
`));let o=await
|
|
240
|
+
`)),v.start("Detecting project setup...");let s=await oe(r);v.succeed("Project setup detected"),f(O.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),f(O.dim(` HTTP Client: ${s.httpClient}`)),f(O.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
|
|
241
|
+
`));let o=await at(t,s.hasRedux,s.httpClient,i.skipStore,i.store,i.skipService,i.service),n=i.path||De.join("src","features"),c=De.join(r,n,o.featureName);await ct(r,o.featureName,n)&&(R(`Feature '${o.featureName}' already exists at ${n}!`),process.exit(1)),v.start("Generating feature files..."),await lt({featureName:o.featureName,featurePath:c,createStore:o.createStore,persistStore:o.persistStore,createService:o.createService,httpClient:o.selectedHttpClient}),v.succeed("Feature files generated"),o.createService&&(v.start("Registering API endpoints..."),await ge({serviceName:o.featureName,projectPath:r}),v.succeed("API endpoints registered")),o.createStore&&s.hasRedux&&(v.start("Registering feature in rootReducer..."),await dt(r,o.featureName,o.persistStore,n),v.succeed("Feature registered in rootReducer"));let m=De.join(n,o.featureName);f(O.green(`
|
|
240
242
|
\u2728 Feature '${o.featureName}' created successfully!
|
|
241
|
-
`)),
|
|
242
|
-
`)),
|
|
243
|
+
`)),f(O.dim("Generated files:")),f(O.dim(` \u{1F4C2} ${m}/`)),f(O.dim(" \u251C\u2500\u2500 components/")),f(O.dim(" \u251C\u2500\u2500 hooks/")),f(O.dim(" \u251C\u2500\u2500 types/")),o.createStore&&f(O.dim(" \u251C\u2500\u2500 store/")),o.createService&&f(O.dim(" \u251C\u2500\u2500 services/")),f(O.dim(` \u2514\u2500\u2500 index.ts
|
|
244
|
+
`)),f(O.cyan("Next steps:"));let h=n.replace(/^src\//,"@/");f(O.dim(` 1. Import and use the feature: import { ${o.featureName} } from '${h}/${o.featureName}'`)),o.createStore&&f(O.dim(` 2. Customize your Redux slice in: ${m}/store/`)),o.createService&&f(O.dim(` 3. Add API methods in: ${m}/services/${o.featureName}.service.ts`)),f("")}catch(r){v.fail("Feature generation failed"),R(`${r}`),process.exit(1)}})};import k from"picocolors";import K from"node:path";import{existsSync as uo}from"node:fs";import{mkdir as fo}from"node:fs/promises";import oo from"enquirer";var{prompt:ro}=oo,gt=async(e,t,i)=>{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."}),t===void 0&&i===void 0&&r.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let s=r.length>0?await ro(r):{};return{sliceName:e||s.sliceName,persistSlice:t===!0?!0:i===!1?!1:s.persistSlice||!1}};import{writeFile as ae,mkdir as no}from"node:fs/promises";import ce from"node:path";var xt=async e=>{let{sliceName:t,slicePath:i,persistSlice:r}=e;await no(i,{recursive:!0});let s=z(t),o=L(t);await so(t,i,s),await ao(t,i,s,o),await co(t,i,s,o),r&&await lo(t,i,s,o),await po(t,i,r)},so=async(e,t,i)=>{let r=`export interface ${i}State {
|
|
243
245
|
loading: boolean;
|
|
244
246
|
error: string | null;
|
|
245
247
|
// Add your state properties here
|
|
246
248
|
}
|
|
247
|
-
`;await
|
|
248
|
-
import { ${
|
|
249
|
+
`;await ae(ce.join(t,`${e}.types.ts`),r)},ao=async(e,t,i,r)=>{let s=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
250
|
+
import { ${i}State } from './${e}.types';
|
|
249
251
|
|
|
250
|
-
const initialState: ${
|
|
252
|
+
const initialState: ${i}State = {
|
|
251
253
|
loading: false,
|
|
252
254
|
error: null,
|
|
253
255
|
// Add your initial state here
|
|
@@ -273,32 +275,32 @@ export const ${r}Slice = createSlice({
|
|
|
273
275
|
export const { setLoading, setError, resetState } = ${r}Slice.actions;
|
|
274
276
|
|
|
275
277
|
export const ${r}Reducer = ${r}Slice.reducer;
|
|
276
|
-
`;await
|
|
278
|
+
`;await ae(ce.join(t,`${e}.slice.ts`),s)},co=async(e,t,i,r)=>{let s=`import { RootState } from '@/store/rootReducer';
|
|
277
279
|
|
|
278
|
-
export const select${
|
|
280
|
+
export const select${i}State = (state: RootState) => state.${r};
|
|
279
281
|
export { setLoading, setError, resetState } from './${e}.slice';
|
|
280
|
-
`;await
|
|
282
|
+
`;await ae(ce.join(t,`${e}.selectors.ts`),s)},lo=async(e,t,i,r)=>{let s=`import { PersistConfig } from 'redux-persist';
|
|
281
283
|
import storage from 'redux-persist/lib/storage';
|
|
282
|
-
import { ${
|
|
284
|
+
import { ${i}State } from './${e}.types';
|
|
283
285
|
|
|
284
|
-
export const ${r}PersistConfig: PersistConfig<${
|
|
286
|
+
export const ${r}PersistConfig: PersistConfig<${i}State> = {
|
|
285
287
|
key: '${r}',
|
|
286
288
|
storage,
|
|
287
289
|
// whitelist: ['someField'], // Specify which fields to persist
|
|
288
290
|
};
|
|
289
|
-
`;await
|
|
291
|
+
`;await ae(ce.join(t,"persist.ts"),s)},po=async(e,t,i)=>{let r=`export * from './${e}.slice';
|
|
290
292
|
export * from './${e}.selectors';
|
|
291
|
-
export * from './${e}.types';${
|
|
293
|
+
export * from './${e}.types';${i?`
|
|
292
294
|
export * from './persist';`:""}
|
|
293
|
-
`;await
|
|
295
|
+
`;await ae(ce.join(t,"index.ts"),r)};import{access as mo}from"node:fs/promises";import ht from"node:path";var yt=async(e,t,i=ht.join("src","store","slices"))=>{let r=ht.join(e,i,t);try{return await mo(r),!0}catch{return!1}};var St=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(t,i)=>{try{let r=process.cwd();i.persist&&i.noPersist===!0&&(R("Cannot use --persist and --no-persist together"),process.exit(1)),f(k.cyan(`
|
|
294
296
|
\u{1F527} Slice Generator
|
|
295
|
-
`)),
|
|
297
|
+
`)),v.start("Detecting project setup...");let s=await oe(r);v.succeed("Project setup detected"),s.hasRedux||(v.fail("Redux is not setup in this project"),R("Please install @reduxjs/toolkit and react-redux first"),f(k.dim(`
|
|
296
298
|
Run: npm install @reduxjs/toolkit react-redux
|
|
297
|
-
`)),process.exit(1)),
|
|
298
|
-
`));let o=await
|
|
299
|
+
`)),process.exit(1)),f(k.dim(` Redux: \u2713
|
|
300
|
+
`));let o=await gt(t,i.persist,i.noPersist===!0?!1:void 0),n,c,p;if(i.path){let w=i.path.replace(/^src\//,"");w.startsWith("features/")?(c=w.split("/")[1],n=K.join("src","features",c,"store"),p=K.join(r,n,o.sliceName)):(n=K.join("src",w),c=w.split("/")[0],p=K.join(r,n,o.sliceName))}else c=o.sliceName,n=K.join("src","features",c,"store"),p=K.join(r,n,o.sliceName);let m=K.join(r,n);uo(m)||await fo(m,{recursive:!0}),await yt(r,o.sliceName,n)&&(R(`Slice '${o.sliceName}' already exists at ${n}!`),process.exit(1)),v.start("Generating slice files..."),await xt({sliceName:o.sliceName,slicePath:p,persistSlice:o.persistSlice}),v.succeed("Slice files generated"),v.start("Registering slice in rootReducer..."),await ut(r,o.sliceName,o.persistSlice,n),v.succeed("Slice registered in rootReducer");let y=K.join(n,o.sliceName);f(k.green(`
|
|
299
301
|
\u2728 Slice '${o.sliceName}' created successfully!
|
|
300
|
-
`)),
|
|
301
|
-
`)),
|
|
302
|
+
`)),f(k.dim("Generated files:")),f(k.dim(` \u{1F4C2} ${y}/`)),f(k.dim(` \u251C\u2500\u2500 ${o.sliceName}.slice.ts`)),f(k.dim(` \u251C\u2500\u2500 ${o.sliceName}.selectors.ts`)),o.persistSlice&&f(k.dim(" \u251C\u2500\u2500 persist.ts")),f(k.dim(` \u251C\u2500\u2500 ${o.sliceName}.types.ts`)),f(k.dim(` \u2514\u2500\u2500 index.ts
|
|
303
|
+
`)),f(k.cyan("Next steps:"));let x=n.replace(/^src\//,"@/");f(k.dim(` 1. Import actions: import { setLoading, setError } from '${x}/${o.sliceName}'`)),f(k.dim(" 2. Use in component: dispatch(setLoading(true))")),f("")}catch(r){v.fail("Slice generation failed"),R(`${r}`),process.exit(1)}})};import X from"picocolors";import Q from"node:path";import{existsSync as Po}from"node:fs";import{mkdir as vo}from"node:fs/promises";import Pt from"enquirer";var vt=async(e,t,i,r)=>{let s=e||(await Pt.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 t!==void 0?o="axios":i!==void 0?o="fetch":r==="axios"?o="axios":r==="fetch"?o="fetch":r==="both"?o=(await Pt.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:o="axios",{serviceName:s,httpClient:o}};import{writeFile as go}from"node:fs/promises";import xo from"node:path";var wt=async e=>{await ho(e)},ho=async e=>{let{serviceName:t,servicePath:i,httpClient:r}=e,s=L(t),o;r==="axios"?o=`import { AppApis } from '@/lib/config';
|
|
302
304
|
import { axiosClient } from '@/lib/utils/http';
|
|
303
305
|
import { ResultAsync } from '@/types';
|
|
304
306
|
|
|
@@ -316,25 +318,25 @@ export const ${s}Service = {
|
|
|
316
318
|
return fetchClient.get<string>(AppApis.${s}.getAll);
|
|
317
319
|
},
|
|
318
320
|
};
|
|
319
|
-
`;let n=`${
|
|
321
|
+
`;let n=`${t}.service.ts`;await go(xo.join(i,n),o)};import{existsSync as yo}from"node:fs";import So from"node:path";var Ct=async(e,t,i)=>{let r=So.join(e,i,`${t}.service.ts`);return yo(r)};var Tt=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(t,i)=>{try{let r=process.cwd();i.axios&&i.fetch&&(R("Cannot use --axios and --fetch together"),process.exit(1)),f(X.cyan(`
|
|
320
322
|
\u{1F527} Service Generator
|
|
321
|
-
`)),
|
|
323
|
+
`)),v.start("Detecting project setup...");let s=await oe(r);v.succeed("Project setup detected"),s.httpClient==="none"&&(v.fail("No HTTP client is setup in this project"),R("Please setup either AxiosClient or FetchClient first"),f(X.dim(`
|
|
322
324
|
Check: lib/utils/http/axios-client or lib/utils/http/fetch-client
|
|
323
|
-
`)),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"),
|
|
324
|
-
`));let n=await
|
|
325
|
+
`)),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"),f(X.dim(` HTTP Clients: ${o.join(", ")}
|
|
326
|
+
`));let n=await vt(t,i.axios,i.fetch,s.httpClient),c,p,m;if(i.path){let w=i.path.replace(/^src\//,"");w.startsWith("features/")?(p=w.split("/")[1],c=Q.join("src","features",p,"services"),m=Q.join(r,c)):(c=Q.join("src",w),p=w.split("/")[0],m=Q.join(r,c))}else p=n.serviceName,c=Q.join("src","features",p,"services"),m=Q.join(r,c);Po(m)||await vo(m,{recursive:!0}),await Ct(r,n.serviceName,c)&&(R(`Service '${n.serviceName}' already exists at ${c}!`),process.exit(1)),v.start("Generating service files..."),await wt({serviceName:n.serviceName,servicePath:m,httpClient:n.httpClient}),v.succeed("Service files generated"),v.start("Registering API endpoints..."),await ge({serviceName:n.serviceName,projectPath:r}),v.succeed("API endpoints registered");let y=Q.join(c,`${n.serviceName}.service.ts`);f(X.green(`
|
|
325
327
|
\u2728 Service '${n.serviceName}' created successfully!
|
|
326
|
-
`)),
|
|
327
|
-
`)),
|
|
328
|
-
`,await
|
|
329
|
-
`),
|
|
330
|
-
`+
|
|
331
|
-
`+
|
|
332
|
-
<CustomThemeProvider>`),
|
|
333
|
-
</StoreProvider>`);else{let o=
|
|
328
|
+
`)),f(X.dim("Generated files:")),f(X.dim(` \u{1F4C4} ${y}
|
|
329
|
+
`)),f(X.cyan("Next steps:"));let x=c.replace(/^src\//,"@/");f(X.dim(` 1. Import service: import { ${n.serviceName}Service } from '${x}/${n.serviceName}.service'`)),f(X.dim(` 2. Use in component: const data = await ${n.serviceName}Service.getAll()`)),f("")}catch(r){v.fail("Service generation failed"),R(`${r}`),process.exit(1)}})};import we from"picocolors";import Do from"enquirer";T();import Co from"node:path";import To from"picocolors";T();N();import le from"node:path";T();N();import Et from"node:path";var xe=async e=>{let t=[Et.join(e,a.ROOT_LAYOUT),Et.join(e,"src/app/[locale]/layout.tsx")];for(let i of t)if(l(i)&&(await d(i)).includes("<body"))return i;for(let i of t)if(l(i))return i;return""};var It=async e=>{let t=le.join(e,a.THEME_PROVIDER),i=le.join(e,a.GLOBALS_CSS),r=le.join(e,"package.json");if(l(t))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(i)&&(await d(i)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},Rt=async e=>{let t=le.join(e,a.GLOBALS_CSS),i=le.join(e,a.PROVIDERS_INDEX),r=await xe(e);if(!l(t)||!r||!l(i))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};T();N();import Nt from"node:path";import wo from"degit";var At=async(e,t)=>{t.text="Fetching assets from starter repo...",await wo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},Ot=async(e,t)=>{let i=Nt.join(e,a.THEME_PROVIDER),r=Nt.join(t,"src/providers/CustomThemeProvider.tsx");await b(r,i)};T();N();import he from"node:path";var $t=async e=>{let t=he.join(e,a.PROVIDERS_INDEX),i=await d(t);i.includes("CustomThemeProvider")||(i+=`export * from './CustomThemeProvider';
|
|
330
|
+
`,await u(t,i))},_t=async e=>{let t=he.join(e,"src/providers/RootProvider.tsx");if(l(t)){let i=await d(t),r="'use client';",s=i.includes(r);if(s&&(i=i.replace(r,"").trim()),i.includes("CustomThemeProvider")||(i=i.replace(/import \{ StoreProvider \} from '@\/providers';\n/,`import { StoreProvider, CustomThemeProvider } from '@/providers';
|
|
331
|
+
`),i.includes("CustomThemeProvider")||(i.includes("from '@/providers'")?i=i.replace(/\} from '@\/providers'/,", CustomThemeProvider } from '@/providers'"):i=`import { CustomThemeProvider } from '@/providers';
|
|
332
|
+
`+i)),s&&(i=r+`
|
|
333
|
+
`+i),!i.includes("<CustomThemeProvider>")){if(i.includes("<StoreProvider>"))i=i.replace(/<StoreProvider>/,`<StoreProvider>
|
|
334
|
+
<CustomThemeProvider>`),i=i.replace(/<\/StoreProvider>/,`</CustomThemeProvider>
|
|
335
|
+
</StoreProvider>`);else{let o=i.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];i=i.replace(o[0],`return (
|
|
334
336
|
<CustomThemeProvider>
|
|
335
337
|
${n}
|
|
336
338
|
</CustomThemeProvider>
|
|
337
|
-
);`)}}await
|
|
339
|
+
);`)}}await u(t,i)}}},bt=async(e,t)=>{let i=he.join(e,a.GLOBALS_CSS),r=he.join(t,"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+=`
|
|
338
340
|
${c[0]}
|
|
339
341
|
`),p&&(s+=`
|
|
340
342
|
${p[0]}
|
|
@@ -345,32 +347,32 @@ ${p[0]}
|
|
|
345
347
|
--color-dark: #202938;
|
|
346
348
|
--color-light: #f5f5f5;
|
|
347
349
|
}
|
|
348
|
-
`);let o=await
|
|
349
|
-
`,n);o=o.slice(0,c+1)+s+o.slice(c+1)}else o=s+o;await
|
|
350
|
-
`,await
|
|
351
|
-
`+
|
|
352
|
-
`+
|
|
350
|
+
`);let o=await d(i);if(!o.includes("@custom-variant dark")){if(o.includes("@import")){let n=o.lastIndexOf("@import"),c=o.indexOf(`
|
|
351
|
+
`,n);o=o.slice(0,c+1)+s+o.slice(c+1)}else o=s+o;await u(i,o)}},Ft=async e=>{let t=await d(e);t.includes("dark:bg-dark")||(t=t.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await u(e,t))};var Le=async e=>{let t=$("Setting up Dark Theme..."),i=Co.join(e,".next-maker-temp");try{let{isSetup:r,reason:s}=await It(e);if(r){t.fail(`Dark Theme is already set up (${s}).`);return}let o=await Rt(e);await At(i,t),await Ot(e,i),await $t(e),await _t(e),await bt(e,i),await Ft(o),t.text="Installing next-themes...",await M(e,"next-themes"),t.text="Formatting code...";let n=await G(e);await H(e,n,"format"),t.succeed(To.green("Dark Theme setup successfully!"))}catch(r){throw t.fail("Failed to setup Dark Theme."),r}finally{await S(i)}};T();import Io from"node:path";import Ro from"picocolors";T();N();import Me from"node:path";var jt=async e=>{let t=Me.join(e,a.STORE),i=Me.join(e,"package.json");if(l(t))return{isSetup:!0,reason:"src/store directory exists"};if(l(i)){let r=JSON.parse(await d(i));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:""}},kt=async e=>{let t=Me.join(e,a.PROVIDERS_INDEX);if(!await xe(e)||!l(t))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx (or src/app/[locale]/layout.tsx) and src/providers/index.ts exist.")};T();N();import ee from"node:path";import Eo from"degit";import Dt from"node:fs/promises";var Lt=async(e,t)=>{t.text="Fetching assets from starter repo...",await Eo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},Mt=async(e,t)=>{let i=ee.join(t,"src/providers/StoreProvider.tsx"),r=ee.join(e,a.STORE_PROVIDER);await b(i,r);let s=ee.join(t,"src/store"),o=ee.join(e,a.STORE);await Dt.cp(s,o,{recursive:!0})},Ht=async(e,t)=>{let i=ee.join(t,"src/features/counter"),r=ee.join(e,a.COUNTER_FEATURE);await Dt.cp(i,r,{recursive:!0});let s=ee.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)}};T();N();import ye from"node:path";var Gt=async e=>{let t=ye.join(e,a.PROVIDERS_INDEX),i=await d(t);i.includes("StoreProvider")||(i+=`export * from './StoreProvider';
|
|
352
|
+
`,await u(t,i))},Ut=async e=>{let t=ye.join(e,"src/providers/RootProvider.tsx");if(l(t)){let i=await d(t),r="'use client';",s=i.includes(r);if(s&&(i=i.replace(r,"").trim()),i.includes("StoreProvider")||(i=i.replace(/import \{ (.*?) \} from '@\/providers';/,"import { $1, StoreProvider } from '@/providers';"),i.includes("StoreProvider")||(i.includes("from '@/providers'")?i=i.replace(/\} from '@\/providers'/,", StoreProvider } from '@/providers'"):i=`import { StoreProvider } from '@/providers';
|
|
353
|
+
`+i)),s&&(i=r+`
|
|
354
|
+
`+i),!i.includes("<StoreProvider>")){let o=i.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(o){let n=o[1];i=i.replace(o[0],`return (
|
|
353
355
|
<StoreProvider>
|
|
354
356
|
${n}
|
|
355
357
|
</StoreProvider>
|
|
356
|
-
);`),await
|
|
358
|
+
);`),await u(t,i)}}}},Yt=async e=>{let t=[ye.join(e,a.ROOT_PAGE),ye.join(e,"src/app/[locale]/page.tsx")],i="";for(let r of t)if(l(r)){i=r;break}if(i){let r=await d(i);if(r.includes("Counter")||(r=`import { Counter } from '@/features/counter/components/Counter';
|
|
357
359
|
`+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)+`
|
|
358
360
|
<div className="mt-8">
|
|
359
361
|
<h2 className="text-2xl font-bold mb-4">Redux Counter</h2>
|
|
360
362
|
<Counter />
|
|
361
363
|
</div>
|
|
362
|
-
`+r.slice(n),await
|
|
363
|
-
`+
|
|
364
|
+
`+r.slice(n),await u(i,r))}}};var He=async e=>{let t=$("Setting up Redux Toolkit..."),i=Io.join(e,".next-maker-temp-redux");try{let{isSetup:r,reason:s}=await jt(e);if(r){t.fail(`Redux is already set up (${s}).`);return}await kt(e),await Lt(i,t),t.text="Copying Redux files...",await Mt(e,i),t.text="Creating Counter feature...",await Ht(e,i),t.text="Updating providers and pages...",await Gt(e),await Ut(e),await Yt(e),t.text="Installing dependencies...",await M(e,"@reduxjs/toolkit"),await M(e,"react-redux"),await M(e,"redux-persist"),await M(e,"react-secure-storage"),t.text="Formatting code...";let o=await G(e);await H(e,o,"format"),t.succeed(Ro.green("Redux Toolkit setup successfully!"))}catch(r){throw t.fail("Failed to setup Redux Toolkit."),r}finally{await S(i)}};T();import $o from"node:path";import _o from"picocolors";T();N();import Se from"node:path";var Xt=async e=>{let t=Se.join(e,a.I18N_DIR),i=Se.join(e,"package.json");if(l(t))return{isSetup:!0,reason:"src/i18n directory exists"};if(l(i)){let r=JSON.parse(await d(i));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:""}},Jt=async e=>{let t=Se.join(e,a.ROOT_LAYOUT),i=Se.join(e,"src/app/[locale]/layout.tsx");if(!l(t)&&!l(i))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx exists.")};T();N();import B from"node:path";import No from"degit";import Ao from"node:fs/promises";var Wt=async(e,t)=>{t.text="Fetching assets from starter repo...",await No("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},zt=async(e,t)=>{let i=B.join(t,"src/i18n"),r=B.join(e,a.I18N_DIR);await Ao.cp(i,r,{recursive:!0});let s=B.join(t,"src/proxy.ts"),o=B.join(e,a.PROXY);await b(s,o);let n=B.join(t,"src/types/i18n.ts"),c=B.join(e,a.I18N_TYPES);await b(n,c);let p=B.join(t,"src/lib/config/app-locales.ts"),m=B.join(e,a.APP_LOCALES);await b(p,m)};T();N();import J from"node:path";import Oo from"node:fs/promises";var Vt=async e=>{let t=J.join(e,a.NEXT_CONFIG);if(l(t)){let i=await d(t);if(!i.includes("createNextIntlPlugin")){i=`import createNextIntlPlugin from 'next-intl/plugin';
|
|
365
|
+
`+i;let r=/export default (.*?);/;r.test(i)?i=i.replace(r,`
|
|
364
366
|
const withNextIntl = createNextIntlPlugin();
|
|
365
|
-
export default withNextIntl($1);`):(
|
|
367
|
+
export default withNextIntl($1);`):(i+=`
|
|
366
368
|
const withNextIntl = createNextIntlPlugin();
|
|
367
|
-
`,
|
|
368
|
-
`),await
|
|
369
|
-
`,await
|
|
370
|
-
`,await
|
|
369
|
+
`,i+=`export default withNextIntl(nextConfig);
|
|
370
|
+
`),await u(t,i)}}},Kt=async e=>{let t=J.join(e,a.TYPES_INDEX);if(l(t)){let i=await d(t);i.includes("./i18n")||(i+=`export * from './i18n';
|
|
371
|
+
`,await u(t,i))}},Bt=async e=>{let t=J.join(e,a.CONFIG_INDEX);if(l(t)){let i=await d(t);i.includes("./app-locales")||(i+=`export * from './app-locales';
|
|
372
|
+
`,await u(t,i))}},qt=async e=>{let t=J.join(e,"src/providers/RootProvider.tsx");if(l(t)){let i=await d(t),r="'use client';",s=i.includes(r);if(s&&(i=i.replace(r,"").trim()),i.includes("next-intl")||(i=`import { SupportedLocale } from '@/types/i18n';
|
|
371
373
|
import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';
|
|
372
|
-
`+
|
|
373
|
-
`+
|
|
374
|
+
`+i),s&&(i=r+`
|
|
375
|
+
`+i),!i.includes("locale: SupportedLocale")){let o=/export const RootProvider = \(\{([\s\S]*?)\}: \{([\s\S]*?)\}\) => \{/,n=i.match(o);n&&(i=i.replace(n[0],`export const RootProvider = ({
|
|
374
376
|
children,
|
|
375
377
|
locale,
|
|
376
378
|
messages,
|
|
@@ -378,26 +380,26 @@ import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';
|
|
|
378
380
|
children: React.ReactNode;
|
|
379
381
|
locale: SupportedLocale;
|
|
380
382
|
messages: AbstractIntlMessages;
|
|
381
|
-
}) => {`))}if(!
|
|
383
|
+
}) => {`))}if(!i.includes("<NextIntlClientProvider")){let o=i.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}>
|
|
382
384
|
{children}
|
|
383
|
-
</NextIntlClientProvider>`);
|
|
385
|
+
</NextIntlClientProvider>`);i=i.replace(o[0],`return (
|
|
384
386
|
${c}
|
|
385
|
-
);`)}else
|
|
387
|
+
);`)}else i=i.replace(o[0],`return (
|
|
386
388
|
<NextIntlClientProvider locale={locale} messages={messages}>
|
|
387
389
|
${n}
|
|
388
390
|
</NextIntlClientProvider>
|
|
389
|
-
);`)}}await
|
|
391
|
+
);`)}}await u(t,i)}},Zt=async e=>{let t=J.join(e,a.ROOT_LAYOUT),i=J.join(e,a.ROOT_PAGE),r=J.join(e,"src/app/[locale]");if(await Oo.mkdir(r,{recursive:!0}),l(t)){let s=J.join(r,"layout.tsx"),o=await d(t);if(o.includes("next-intl")||(o=`import { routing } from '@/i18n/routing';
|
|
390
392
|
import { hasLocale } from 'next-intl';
|
|
391
393
|
import { notFound } from 'next/navigation';
|
|
392
394
|
import { setRequestLocale, getMessages } from 'next-intl/server';
|
|
393
|
-
`+o),!o.includes("generateStaticParams")){let p=o.indexOf("};",o.indexOf("export const metadata"));if(p!==-1){let
|
|
395
|
+
`+o),!o.includes("generateStaticParams")){let p=o.indexOf("};",o.indexOf("export const metadata"));if(p!==-1){let m=p+2;o=o.slice(0,m)+`
|
|
394
396
|
|
|
395
397
|
export function generateStaticParams() {
|
|
396
398
|
return routing.locales.map((locale) => ({ locale }));
|
|
397
|
-
}`+o.slice(
|
|
399
|
+
}`+o.slice(m)}}o=o.replace(/Readonly<\{\s*children:\s*React\.ReactNode;\s*}>/,`Readonly<{
|
|
398
400
|
children: React.ReactNode;
|
|
399
401
|
params: Promise<{ locale: string }>;
|
|
400
|
-
}>`);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
|
|
402
|
+
}>`);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 m=/export default async function RootLayout[\s\S]*?\)\s*\{/,h=o.match(m);if(h&&h.index!==void 0){let y=h.index+h[0].length-1;o=o.slice(0,y+1)+`
|
|
401
403
|
const { locale } = await params;
|
|
402
404
|
|
|
403
405
|
if (!hasLocale(routing.locales, locale)) {
|
|
@@ -407,7 +409,7 @@ export function generateStaticParams() {
|
|
|
407
409
|
setRequestLocale(locale);
|
|
408
410
|
|
|
409
411
|
const messages = await getMessages();
|
|
410
|
-
`+o.slice(
|
|
412
|
+
`+o.slice(y+1)}o=o.replace(/<RootProvider>/,"<RootProvider locale={locale} messages={messages}>"),o=o.replace(/<html lang="en"/,"<html lang={locale}")}await u(s,o),await C(t)}if(l(i)){let s=J.join(r,"page.tsx"),o=await d(i);o.includes("next-intl")||(o=`import { SupportedLocale } from '@/types/i18n';
|
|
411
413
|
import { setRequestLocale } from 'next-intl/server';
|
|
412
414
|
`+o),o=o.replace(/export default function Home\(\)/,`type Props = {
|
|
413
415
|
params: Promise<{ locale: string }>;
|
|
@@ -416,10 +418,17 @@ import { setRequestLocale } from 'next-intl/server';
|
|
|
416
418
|
export default async function Home(props: Props)`);let n=o.indexOf("export default async function Home(props: Props) {");if(n!==-1){let c=`
|
|
417
419
|
const locale = (await props.params).locale as SupportedLocale;
|
|
418
420
|
setRequestLocale(locale);
|
|
419
|
-
`,p=o.indexOf("{",n);o=o.slice(0,p+1)+c+o.slice(p+1)}await
|
|
420
|
-
${
|
|
421
|
-
`)}`)};import
|
|
421
|
+
`,p=o.indexOf("{",n);o=o.slice(0,p+1)+c+o.slice(p+1)}await u(s,o),await C(i)}};var Ge=async e=>{let t=$("Setting up Internationalization (next-intl)..."),i=$o.join(e,".next-maker-temp-i18n");try{let{isSetup:r,reason:s}=await Xt(e);if(r){t.fail(`i18n is already set up (${s}).`);return}await Jt(e),await Wt(i,t),t.text="Copying i18n files...",await zt(e,i),t.text="Configuring project structure...",await Vt(e),await Kt(e),await Bt(e),await qt(e),t.text="Migrating to [locale] structure...",await Zt(e),t.text="Installing dependencies...",await M(e,"next-intl"),t.text="Formatting code...";let o=await G(e);await H(e,o,"format"),t.succeed(_o.green("Internationalization setup successfully!"))}catch(r){throw t.fail("Failed to setup Internationalization."),r}finally{await S(i)}};T();import Pe from"node:path";import Fo from"node:fs/promises";import Ue from"picocolors";import ve from"enquirer";T();N();import pe from"node:path";var Qt=async e=>{let t=pe.join(e,a.FETCH_CLIENT_FILE),i=pe.join(e,a.AXIOS_CLIENT_FILE),r=l(t),s=l(i);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"}},ei=async e=>{let i=[pe.join(e,"src/lib"),pe.join(e,"src/types"),pe.join(e,"src/lib/config")].filter(r=>!l(r));if(i.length>0)throw new Error(`Invalid project structure. Missing directories:
|
|
422
|
+
${i.map(r=>`- ${r}`).join(`
|
|
423
|
+
`)}`)};T();N();import P from"node:path";import bo from"degit";import W from"node:fs/promises";var ti=async(e,t)=>{t.text="Downloading assets from starter repository...",await bo("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},ii=async(e,t,i,r)=>{let s=P.join(e,a.HTTP_UTILS),o=P.join(t,a.HTTP_UTILS);await W.cp(P.join(t,a.ERRORS_DIR),P.join(e,a.ERRORS_DIR),{recursive:!0});let n=P.join(e,a.APP_APIS);l(n)||await b(P.join(t,a.APP_APIS),n);let c=P.join(e,a.CONSTANTS);if(!l(c))await b(P.join(t,a.CONSTANTS),c);else{let m=await d(c),h=!1;m.includes("API_RESPONSE_DATA_KEY")||(m+=`
|
|
424
|
+
export const API_RESPONSE_DATA_KEY = 'data';
|
|
425
|
+
`,h=!0),m.includes("SAVE_AUTH_TOKENS")||(m+=`
|
|
426
|
+
export const SAVE_AUTH_TOKENS = false;
|
|
427
|
+
`,h=!0),h&&await u(c,m)}let p=P.join(e,a.STORAGE_SERVICE);if(l(p)||await W.cp(P.join(t,a.STORAGE_SERVICE),p,{recursive:!0}),await W.cp(P.join(t,a.COMMON_TYPES_DIR),P.join(e,a.COMMON_TYPES_DIR),{recursive:!0}),await W.cp(P.join(t,a.UTILITY_TYPES_DIR),P.join(e,a.UTILITY_TYPES_DIR),{recursive:!0}),await b(P.join(o,"token-store.ts"),P.join(s,"token-store.ts")),await b(P.join(o,"client-utils.ts"),P.join(s,"client-utils.ts")),r&&r.length>0)for(let m of r){let h=P.join(e,m==="fetch"?a.FETCH_CLIENT:a.AXIOS_CLIENT);await S(h)}for(let m of i)m==="fetch"?await W.cp(P.join(t,a.FETCH_CLIENT),P.join(e,a.FETCH_CLIENT),{recursive:!0}):await W.cp(P.join(t,a.AXIOS_CLIENT),P.join(e,a.AXIOS_CLIENT),{recursive:!0});await b(P.join(o,"index.ts"),P.join(s,"index.ts")),await b(P.join(t,a.HTTP_TYPES),P.join(e,a.HTTP_TYPES))},oi=async e=>{let{isFileUsed:t,isStringUsed:i}=await Promise.resolve().then(()=>(fe(),et));await S(P.join(e,a.HTTP_UTILS));let r=P.join(e,a.STORAGE_SERVICE);l(r)&&(await i(e,"SecureStorageService",[r])||await S(r));let s=P.join(e,a.CONSTANTS);if(l(s)){let p=await d(s),m=!1;await i(e,"API_RESPONSE_DATA_KEY",[s])||(p=p.replace(/export const API_RESPONSE_DATA_KEY = .*;\n?/g,""),m=!0),await i(e,"SAVE_AUTH_TOKENS",[s])||(p=p.replace(/export const SAVE_AUTH_TOKENS = .*;\n?/g,""),m=!0),m&&(p=p.replace(/\n\s*\n/g,`
|
|
428
|
+
|
|
429
|
+
`).trim()+`
|
|
430
|
+
`,await u(s,p))}let o=P.join(e,a.ERRORS_DIR);if(l(o)){let p=await W.readdir(o),m=!1;for(let h of p){let y=P.parse(h).name;if(await t(e,y,[P.join(o,h)])){m=!0;break}}m||await S(o)}let n=P.join(e,a.COMMON_TYPES_DIR);l(n)&&(await W.readdir(n)).length===0&&await S(n);let c=P.join(e,a.UTILITY_TYPES_DIR);l(c)&&(await W.readdir(c)).length===0&&await S(c)};fe();var Ye=async e=>{let t=$("Checking HTTP Client setup..."),i=Pe.join(e,".next-maker-temp-http");try{let{status:r,reason:s}=await Qt(e);t.stop();let o=await jo(r,s);if(o.type==="cancel"){console.log(Ue.yellow("Setup cancelled."));return}if(t.start("Setting up HTTP client(s)..."),await ei(e),await ti(i,t),o.type==="replace"&&o.fromClient&&(t.text="Migrating client usages...",await $e(e,o.fromClient,o.clients[0])),o.type!=="remove-both"&&o.type!=="remove-one"){t.text="Copying client files...";let w=o.type==="replace"&&o.fromClient?[o.fromClient]:void 0;await ii(e,i,o.clients,w)}if(o.type==="remove-one"||o.type==="remove-both"){t.text="Removing client files...";let{PROJECT_PATHS:w}=await Promise.resolve().then(()=>(N(),Ze));for(let I of o.clients){let F=Pe.join(e,I==="fetch"?w.FETCH_CLIENT:w.AXIOS_CLIENT);await S(F)}ri(r,o).length===0&&(t.text="Performing full cleanup...",await oi(e),await _e(e))}let n=ri(r,o);n.length>0&&(t.text="Configuring client...",await Re(e,n),await Ne(e),await Ae(e),await Oe(e)),await ie(e,n),t.text="Managing dependencies...";let c=Pe.join(e,"package.json"),p=JSON.parse(await Fo.readFile(c,"utf-8")),m={...p.dependencies,...p.devDependencies};n.includes("axios")?m.axios||(t.text="Installing Axios...",await M(e,"axios")):m.axios&&(t.text="Uninstalling Axios...",await Ee(e,"axios"));let h=Pe.join(e,"src/services/storage");n.length>0||l(h)?m["react-secure-storage"]||(t.text="Installing react-secure-storage...",await M(e,"react-secure-storage")):m["react-secure-storage"]&&(t.text="Uninstalling react-secure-storage...",await Ee(e,"react-secure-storage")),t.text="Formatting code...";let x=await G(e);await H(e,x,"format"),t.succeed(Ue.green(ko(o)))}catch(r){throw t.fail("Failed to setup HTTP Client."),r}finally{await S(i)}};async function jo(e,t){if(e==="none"){let{choice:r}=await ve.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 ve.prompt({type:"select",name:"action",message:`${t}. 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 ve.prompt({type:"select",name:"action",message:`${t}. 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(Ue.yellow(`\u2716 ${t}`));let{action:i}=await ve.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 i==="cancel"?{type:"cancel",clients:[]}:i==="remove-fetch"?{type:"remove-one",clients:["fetch"]}:i==="remove-axios"?{type:"remove-one",clients:["axios"]}:i==="remove-both"?{type:"remove-both",clients:["fetch","axios"]}:{type:"cancel",clients:[]}}function ri(e,t){return t.type==="install"?t.clients:t.type==="add"?[...e==="fetch"?["fetch"]:["axios"],...t.clients]:t.type==="replace"?t.clients:t.type==="remove-one"?e==="both"?t.clients[0]==="fetch"?["axios"]:["fetch"]:[]:[]}function ko(e){if(e.type==="install")return`HTTP Client (${e.clients.map(i=>i==="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 t=e.fromClient==="fetch"?"Fetch":"Axios",i=e.clients[0]==="fetch"?"Fetch":"Axios";return`Replaced ${t} with ${i} 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:Lo}=Do,ni=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 t=>{try{if(f(we.cyan(`
|
|
422
431
|
\u{1F527} Setup Wizard
|
|
423
|
-
`)),
|
|
424
|
-
\u26A0\uFE0F ${r} setup is not implemented yet.`)),
|
|
432
|
+
`)),t.httpClient||t.darkTheme||t.redux||t.i18n){t.httpClient&&await Ye(process.cwd()),t.darkTheme&&await Le(process.cwd()),t.redux&&await He(process.cwd()),t.i18n&&await Ge(process.cwd());return}let r=(await Lo([{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"){f(we.yellow("Setup cancelled."));return}r==="dark-theme"?await Le(process.cwd()):r==="redux"?await He(process.cwd()):r==="http-client"?await Ye(process.cwd()):r==="i18n"?await Ge(process.cwd()):(f(we.yellow(`
|
|
433
|
+
\u26A0\uFE0F ${r} setup is not implemented yet.`)),f(we.dim("This feature will be available in a future update.")))}catch(i){v.fail("Setup failed"),R(`${i}`),process.exit(1)}})};var si=e=>{st(e),ni(e),ft(e),St(e),Tt(e)};var Ho=process.emitWarning;process.emitWarning=function(e,t,i,r){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return Ho.apply(process,arguments)};async function Go(){Be({logger:t=>ue(t)});let e=new Mo;e.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),si(e),e.parse()}Go().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);ue(`Unexpected error: ${t}`)});
|
|
425
434
|
//# sourceMappingURL=index.js.map
|