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