@teispace/next-maker 0.2.1 → 0.3.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 +26 -0
- package/README.md +294 -55
- package/dist/index.js +359 -27
- package/dist/index.js.map +4 -4
- package/dist/src/commands/feature.d.ts.map +1 -1
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/service.d.ts +3 -0
- package/dist/src/commands/service.d.ts.map +1 -0
- package/dist/src/commands/slice.d.ts +3 -0
- package/dist/src/commands/slice.d.ts.map +1 -0
- package/dist/src/config/index.d.ts +2 -0
- package/dist/src/config/index.d.ts.map +1 -1
- package/dist/src/config/output.d.ts +1 -0
- package/dist/src/config/output.d.ts.map +1 -1
- package/dist/src/config/paths.d.ts +19 -0
- package/dist/src/config/paths.d.ts.map +1 -1
- package/dist/src/config/utils.d.ts +4 -0
- package/dist/src/config/utils.d.ts.map +1 -1
- package/dist/src/core/package-manager.d.ts.map +1 -1
- package/dist/src/prompts/create-app.prompt.d.ts +1 -0
- package/dist/src/prompts/create-app.prompt.d.ts.map +1 -1
- package/dist/src/prompts/feature.prompt.d.ts +10 -1
- package/dist/src/prompts/feature.prompt.d.ts.map +1 -1
- package/dist/src/prompts/service.prompt.d.ts +7 -0
- package/dist/src/prompts/service.prompt.d.ts.map +1 -0
- package/dist/src/prompts/slice.prompt.d.ts +6 -0
- package/dist/src/prompts/slice.prompt.d.ts.map +1 -0
- package/dist/src/services/feature/detection.service.d.ts +8 -0
- package/dist/src/services/feature/detection.service.d.ts.map +1 -0
- package/dist/src/services/feature/registration.service.d.ts +6 -0
- package/dist/src/services/feature/registration.service.d.ts.map +1 -0
- package/dist/src/services/feature/templates.service.d.ts +10 -0
- package/dist/src/services/feature/templates.service.d.ts.map +1 -0
- package/dist/src/services/init/config.service.d.ts.map +1 -1
- package/dist/src/services/init/providers.service.d.ts.map +1 -1
- package/dist/src/services/service/detection.service.d.ts +2 -0
- package/dist/src/services/service/detection.service.d.ts.map +1 -0
- package/dist/src/services/service/service.service.d.ts +8 -0
- package/dist/src/services/service/service.service.d.ts.map +1 -0
- package/dist/src/services/slice/detection.service.d.ts +2 -0
- package/dist/src/services/slice/detection.service.d.ts.map +1 -0
- package/dist/src/services/slice/slice.service.d.ts +7 -0
- package/dist/src/services/slice/slice.service.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as Se}from"commander";import xe from"node:path";import I from"picocolors";import K from"ora";function x(e="",t){let i=K({text:e,...t});return i.start(),i}import W from"enquirer";var{prompt:B}=W,A=async e=>await B([{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:"input",name:"company",message:"Company name:",initial:"Teispace"},{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:"Git remote origin URL (optional):",validate:i=>i&&!/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/.test(i)?"Please enter a valid URL.":!0},{type:"input",name:"gitIssues",message:"Git issues URL (optional):",validate:i=>i&&!/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/.test(i)?"Please enter a valid URL.":!0},{type:"input",name:"gitHomepage",message:"Project homepage URL (optional):",validate:i=>i&&!/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/.test(i)?"Please enter a valid URL.":!0},{type:"confirm",name:"keepTemplates",message:"Do you want to keep GitHub issue and pull request templates?",initial:!0},{type:"select",name:"httpClient",message:"Which HTTP client do you want to use?",choices:["axios","fetch","both","none"],initial:0},{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:["CODE_OF_CONDUCT.md","CONTRIBUTING.md","SECURITY.md"]},{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:!0},{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:!0},{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}]);import N from"node:fs/promises";import Z from"node:path";import{existsSync as R}from"node:fs";var u=async e=>N.readFile(e,"utf-8"),m=async(e,t)=>{await N.mkdir(Z.dirname(e),{recursive:!0}),await N.writeFile(e,t,"utf-8")},p=async e=>{R(e)&&await N.unlink(e)},d=async e=>{R(e)&&await N.rm(e,{recursive:!0,force:!0})},w=async(e,t)=>{let i=await u(e),o=JSON.parse(i),r=t(o);await m(e,JSON.stringify(r,null,2))},g=e=>R(e);import{exec as q}from"node:child_process";import{promisify as Q}from"node:util";var v=Q(q),D=async e=>{try{await v("git init",{cwd:e}),await v("git add .",{cwd:e}),await v('git commit -m "Initial commit from @teispace/next-maker"',{cwd:e})}catch(t){console.warn("Failed to initialize git repository",t)}},j=async(e,t)=>{try{await v(`git remote add origin ${t}`,{cwd:e})}catch(i){console.warn("Failed to add remote origin",i)}};import{exec as ee}from"node:child_process";import{promisify as te}from"node:util";var L=te(ee),M=async(e,t)=>{let i=`${t} install`;try{await L(i,{cwd:e})}catch(o){throw new Error(`Failed to install dependencies with ${t}: ${o}`)}},O=async(e,t,i)=>{let o=`${t} run ${i}`;try{await L(o,{cwd:e})}catch(r){console.warn(`Warning: Failed to run script '${i}': ${r}`)}};import C from"picocolors";var ie={reset:e=>e,red:C.red,green:C.green,yellow:C.yellow,blue:C.blue,cyan:C.cyan,magenta:C.magenta,white:C.white,gray:C.gray,bright:C.bold,dim:C.dim};function P(e,t="reset"){let i=ie[t]??(o=>o);console.log(i(e))}function _(e){P(`\u2716 ${e}`,"red")}function T(e){P(e)}function b(){console.log(""),P("\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"),P("\u2551 \u2551","cyan"),P("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),P("\u2551 \u2551","cyan"),P("\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 G(e){let{logger:t=a=>console.error(a),exitOnCancel:i=process.env.NODE_ENV!=="test"}=e??{},o=()=>{console.log(""),console.log(""),t("Setup cancelled by user"),console.log(""),i&&process.exit(0)},r=a=>{if(a!==null&&typeof a=="object"&&"code"in a&&a.code==="ERR_USE_AFTER_CLOSE"){o();return}if(a instanceof Error){t(`Uncaught exception: ${a.message}`);return}t(`Uncaught exception: ${String(a)}`)},n=a=>{if(a instanceof Error){t(`Unhandled promise rejection: ${a.message}`);return}t(`Unhandled promise rejection: ${String(a)}`)};return process.on("SIGINT",o),process.on("SIGTERM",o),process.on("uncaughtException",r),process.on("unhandledRejection",n),()=>{process.off("SIGINT",o),process.off("SIGTERM",o),process.off("uncaughtException",r),process.off("unhandledRejection",n)}}import oe from"degit";var U=async e=>{let t=x("Downloading template...");try{await oe("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}};import ne from"node:path";var s={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",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",GITHUB_DIR:".github",HUSKY_DIR:".husky"};var f={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 F=async(e,t)=>{let i=x("Configuring package.json...");try{await w(ne.join(e,s.PACKAGE_JSON),o=>(o.name=t.projectName,o.version=t.version,o.description=t.description,o.author=t.author,delete o.packageManager,t.gitHomepage&&(o.homepage=t.gitHomepage),t.gitIssues&&(o.bugs={url:t.gitIssues}),t.gitRemote&&(o.repository={type:"git",url:t.gitRemote}),t.redux||(delete o.dependencies[f.REDUX_TOOLKIT],delete o.dependencies[f.REACT_REDUX],delete o.dependencies[f.REDUX_PERSIST]),t.httpClient!=="none"||t.reactSecureStorage||delete o.dependencies[f.REACT_SECURE_STORAGE],t.i18n||delete o.dependencies[f.NEXT_INTL],t.darkMode||delete o.dependencies[f.NEXT_THEMES],t.httpClient==="none"?delete o.dependencies[f.AXIOS]:t.httpClient==="fetch"&&delete o.dependencies[f.AXIOS],o)),i.succeed("package.json configured.")}catch(o){throw i.fail("Failed to configure package.json."),o}};import c from"node:path";var k=async(e,t)=>{let i=x("Customizing features...");try{await re(e,t),await ae(e,t),await se(e,t),await ce(e,t),await me(e,t),await pe(e),await le(e),await de(e),i.succeed("Features customized.")}catch(o){throw i.fail("Failed to customize features."),o}},re=async(e,t)=>{let i=c.join(e,s.HTTP_UTILS),o=t.httpClient!=="none"||t.reactSecureStorage;if(t.httpClient==="none"){if(await d(c.join(e,s.AXIOS_CLIENT)),await d(c.join(e,s.FETCH_CLIENT)),o)await m(c.join(i,"index.ts"),`export * from './token-store';
|
|
3
|
-
`);else{await
|
|
4
|
-
${
|
|
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 g(p.join(t,a.CLIENT_UTILS));else{await S(r);let i=p.join(t,a.UTILS_INDEX);if(x(i)){let c=await f(i);c=c.replace(/export \* from '\.\/http';\n/,""),await d(i,c)}await g(p.join(t,a.APP_APIS));let o=p.join(t,a.CONFIG_INDEX);if(x(o)){let c=await f(o);c=c.replace(/export \* from '\.\/app-apis';\n/,""),await d(o,c)}}let n=p.join(t,a.CONSTANTS);if(x(n)){let i=await f(n);i=i.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),i=i.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await d(n,i)}if(await S(p.join(t,a.ERRORS_DIR)),!s){await S(p.join(t,a.COMMON_TYPES_DIR)),await S(p.join(t,a.UTILITY_TYPES_DIR));let i=p.join(t,a.TYPES_INDEX);if(x(i)){let o=await f(i);o=o.replace(/export \* from '\.\/utility';\n/,""),o=o.replace(/export \* from '\.\/common';\n/,""),await d(i,o)}}}else if(e.httpClient==="axios"){await S(p.join(t,a.FETCH_CLIENT));let n=await f(p.join(r,"index.ts"));n=n.replace(/export .* from '\.\/fetch-client';\n/g,""),await d(p.join(r,"index.ts"),n);let i=p.join(t,a.HTTP_TYPES);if(x(i)){let o=await f(i);o=o.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),o=o.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await d(i,o)}}else if(e.httpClient==="fetch"){await S(p.join(t,a.AXIOS_CLIENT));let n=await f(p.join(r,"index.ts"));n=n.replace(/export .* from '\.\/axios-client';\n/g,""),await d(p.join(r,"index.ts"),n);let i=p.join(t,a.HTTP_TYPES);if(x(i)){let o=await f(i);o=o.replace(/declare module 'axios' \{[\s\S]*?\}\n\n/,""),o=o.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await d(i,o)}}},Qe=async(t,e)=>{e.httpClient!=="none"||e.reactSecureStorage||await S(p.join(t,a.STORAGE_SERVICE))},et=async(t,e)=>{if(!e.redux){await S(p.join(t,a.STORE)),await S(p.join(t,a.COUNTER_FEATURE)),await g(p.join(t,a.STORE_PROVIDER));let r=p.join(t,a.PROVIDERS_INDEX),s=await f(r);s=s.replace(/export \* from '\.\/StoreProvider';\n/,""),await d(r,s);let n=[p.join(t,a.ROOT_PAGE),p.join(t,a.LOCALE_PAGE)];for(let i of n)if(x(i)){let o=await f(i);o=o.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),o=o.replace(/<Counter\s*\/>\n?/g,""),await d(i,o)}}},tt=async(t,e)=>{if(!e.darkMode){await g(p.join(t,a.THEME_PROVIDER));let r=p.join(t,a.PROVIDERS_INDEX),s=await f(r);s=s.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await d(r,s);let n=p.join(t,a.GLOBALS_CSS);if(x(n)){let i=await f(n);i=i.replace(/@custom-variant dark \(.*?\);\n\n/,""),i=i.replace(/@theme \{[\s\S]*?\}\n/,""),await d(n,i)}if(!e.i18n){let i=p.join(t,a.ROOT_LAYOUT);if(x(i)){let o=await f(i);o=o.replace(/bg-light dark:bg-dark /g,""),await d(i,o)}}}},rt=async(t,e)=>{if(!e.i18n){await S(p.join(t,a.I18N_DIR)),await S(p.join(t,a.LOCALE_DIR)),await g(p.join(t,a.PROXY)),await g(p.join(t,a.MIDDLEWARE)),await g(p.join(t,a.I18N_TYPES)),await g(p.join(t,a.APP_LOCALES));let r=p.join(t,a.TYPES_INDEX);if(x(r)){let o=await f(r);o=o.replace(/export \* from '\.\/i18n';\n/,""),await d(r,o)}let s=p.join(t,a.CONFIG_INDEX);if(x(s)){let o=await f(s);o=o.replace(/export \* from '\.\/app-locales';\n/,""),await d(s,o)}let n=p.join(t,a.NEXT_CONFIG);if(x(n)){let o=await f(n);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 d(n,o)}let i=p.join(t,a.COUNTER_COMPONENT);if(x(i)){let o=await f(i);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 d(i,o)}}},it=async t=>{await g(p.join(t,a.LICENSE))},ot=async t=>{await g(p.join(t,a.CHANGELOG))},st=async t=>{await g(p.join(t,a.NVM_RC)),await g(p.join(t,a.NPM_RC))};import ee from"node:path";var ge=async(t,e)=>{let r=[],s=[];e.redux&&(r.push("import { StoreProvider } from '@/providers';"),s.push("StoreProvider")),e.darkMode&&(r.push("import { CustomThemeProvider } from '@/providers';"),s.push("CustomThemeProvider")),e.i18n&&(r.push("import { NextIntlClientProvider, AbstractIntlMessages } from 'next-intl';"),r.push("import { SupportedLocale } from '@/types/i18n';"));let n=`'use client';
|
|
4
|
+
${r.join(`
|
|
5
5
|
`)}
|
|
6
6
|
|
|
7
7
|
export const RootProvider = ({
|
|
8
8
|
children,
|
|
9
|
-
${
|
|
9
|
+
${e.i18n?`locale,
|
|
10
10
|
messages,`:""}
|
|
11
11
|
}: {
|
|
12
12
|
children: React.ReactNode;
|
|
13
|
-
${
|
|
13
|
+
${e.i18n?`locale: SupportedLocale;
|
|
14
14
|
messages: AbstractIntlMessages;`:""}
|
|
15
15
|
}) => {
|
|
16
16
|
return (
|
|
17
|
-
`,
|
|
18
|
-
${
|
|
19
|
-
</NextIntlClientProvider>`),
|
|
20
|
-
${
|
|
21
|
-
</CustomThemeProvider>`),
|
|
22
|
-
${
|
|
23
|
-
</StoreProvider>`),
|
|
17
|
+
`,i="{children}";e.i18n&&(i=`<NextIntlClientProvider locale={locale} messages={messages}>
|
|
18
|
+
${i}
|
|
19
|
+
</NextIntlClientProvider>`),e.darkMode&&(i=`<CustomThemeProvider>
|
|
20
|
+
${i}
|
|
21
|
+
</CustomThemeProvider>`),e.redux&&(i=`<StoreProvider>
|
|
22
|
+
${i}
|
|
23
|
+
</StoreProvider>`),i==="{children}"&&(i="<>{children}</>"),n+=` ${i}
|
|
24
24
|
);
|
|
25
25
|
};
|
|
26
|
-
`,await
|
|
26
|
+
`,await d(ee.join(t,a.ROOT_PROVIDER),n)},he=async(t,e)=>{if(!e.i18n){let r=`import type { Metadata } from 'next';
|
|
27
27
|
import '@/styles/globals.css';
|
|
28
28
|
import { Livvic } from 'next/font/google';
|
|
29
29
|
import { RootProvider } from '@/providers';
|
|
@@ -36,8 +36,8 @@ const livvic = Livvic({
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
export const metadata: Metadata = {
|
|
39
|
-
title: '${
|
|
40
|
-
description: '${
|
|
39
|
+
title: '${e.projectName}',
|
|
40
|
+
description: '${e.description}',
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export default function RootLayout({
|
|
@@ -46,8 +46,8 @@ export default function RootLayout({
|
|
|
46
46
|
children: React.ReactNode;
|
|
47
47
|
}>) {
|
|
48
48
|
return (
|
|
49
|
-
<html lang="en" suppressHydrationWarning={true}>
|
|
50
|
-
<body className={\`\${livvic.variable} bg-light dark:bg-dark antialiased\`}>
|
|
49
|
+
<html lang="en" suppressHydrationWarning={${e.darkMode?"true":"false"}}>
|
|
50
|
+
<body className={\`\${livvic.variable} ${e.darkMode?"bg-light dark:bg-dark ":""}antialiased\`}>
|
|
51
51
|
<RootProvider>
|
|
52
52
|
{children}
|
|
53
53
|
</RootProvider>
|
|
@@ -55,29 +55,361 @@ export default function RootLayout({
|
|
|
55
55
|
</html>
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
|
-
`;await
|
|
58
|
+
`;await d(ee.join(t,a.ROOT_LAYOUT),r);let s=e.redux?`import { Counter } from '@/features/counter';
|
|
59
|
+
|
|
60
|
+
`:"",n=e.redux?`
|
|
61
|
+
<Counter />`:"",i=`${s}export default function Home() {
|
|
59
62
|
return (
|
|
60
63
|
<div className="flex min-h-screen flex-col items-center justify-center p-24">
|
|
61
|
-
<h1 className="text-4xl font-bold">Welcome to ${
|
|
62
|
-
<p className="mt-4 text-xl">Get started by editing src/app/page.tsx</p
|
|
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>${n}
|
|
63
66
|
</div>
|
|
64
67
|
);
|
|
65
68
|
}
|
|
66
|
-
`;await
|
|
67
|
-
`};
|
|
69
|
+
`;await d(ee.join(t,a.ROOT_PAGE),i)}};import y from"node:path";import{readdir as xe}from"node:fs/promises";var ye=async(t,e)=>{await nt(t,e),await at(t,e),await ct(t,e),await lt(t,e),await pt(t,e),await mt(t,e),await ut(t,e)},nt=async(t,e)=>{e.preCommitHooks||(await S(y.join(t,a.HUSKY_DIR)),await g(y.join(t,a.COMMITLINT_CONFIG)),await g(y.join(t,a.LINTSTAGED_RC)),await X(y.join(t,a.PACKAGE_JSON),r=>(delete r.devDependencies[v.HUSKY],delete r.devDependencies[v.COMMITLINT_CLI],delete r.devDependencies[v.COMMITLINT_CONFIG],delete r.devDependencies[v.LINT_STAGED],delete r.scripts.prepare,delete r.scripts.postinstall,delete r.commitlint,delete r["lint-staged"],r)))},at=async(t,e)=>{e.commitizen||(await g(y.join(t,a.CZRC)),await X(y.join(t,a.PACKAGE_JSON),r=>(delete r.devDependencies[v.COMMITIZEN],delete r.devDependencies[v.CZ_CONVENTIONAL_CHANGELOG],delete r.config?.commitizen,r.config&&Object.keys(r.config).length===0&&delete r.config,delete r.scripts.commit,r)))},ct=async(t,e)=>{e.ci||await S(y.join(t,a.GITHUB_WORKFLOWS))},lt=async(t,e)=>{let r=y.join(t,a.GITHUB_DIR);if(!e.keepTemplates)await S(y.join(r,a.GITHUB_ISSUE_TEMPLATE)),await g(y.join(r,a.GITHUB_PR_TEMPLATE));else{let s=y.join(r,a.GITHUB_ISSUE_TEMPLATE),n=y.join(r,a.GITHUB_PR_TEMPLATE),i=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(n)){let o=await f(n);o=i(o),await d(n,o)}try{if(x(s)){let o=await xe(s);for(let c of o){let m=y.join(s,c),u=await f(m);u=i(u),await d(m,u)}}}catch{}}},pt=async(t,e)=>{let r=[a.CODE_OF_CONDUCT,a.CONTRIBUTING,a.SECURITY];for(let s of r)e.communityFiles.includes(s)||await g(y.join(t,s))},mt=async(t,e)=>{if(e.docker){let r=y.join(t,a.ENV_EXAMPLE);if(x(r)){let s=await f(r),n=(i,o)=>{let c=new RegExp(`${i}=.*`);c.test(s)?s=s.replace(c,`${i}=${o}`):s+=`${i}=${o}
|
|
70
|
+
`};n("CONTAINER_NAME",e.containerName||"next-app"),n("IMAGE_NAME",e.imageName||"nextjs-starter"),n("IMAGE_TAG",e.imageTag||"latest"),await d(r,s)}}else{await g(y.join(t,a.DOCKERFILE)),await g(y.join(t,a.DOCKER_COMPOSE)),await g(y.join(t,a.DOCKERIGNORE));let r=y.join(t,a.ENV_EXAMPLE);if(x(r)){let s=await f(r);s=s.replace(/# Docker Compose Configuration\n/,""),s=s.replace(/CONTAINER_NAME=.*\n/,""),s=s.replace(/IMAGE_NAME=.*\n/,""),s=s.replace(/IMAGE_TAG=.*\n/,""),await d(r,s)}}},ut=async(t,e)=>{let r=async i=>{let o=await xe(i,{withFileTypes:!0}),c=[];for(let m of o){let u=y.join(i,m.name);m.isDirectory()&&m.name!=="node_modules"&&m.name!==".git"?c.push(...await r(u)):m.isFile()&&m.name.toLowerCase()==="readme.md"&&c.push(u)}return c},s=await r(t),n=y.join(t,a.README);for(let i of s)i!==n&&await g(i);if(e.readme){let i=`# ${e.projectName}
|
|
68
71
|
|
|
69
|
-
${
|
|
72
|
+
${e.description}
|
|
70
73
|
|
|
71
74
|
## Getting Started
|
|
72
75
|
|
|
73
76
|
First, run the development server:
|
|
74
77
|
|
|
75
78
|
\`\`\`bash
|
|
76
|
-
${
|
|
79
|
+
${e.packageManager==="npm"?"npm run dev":e.packageManager+" dev"}
|
|
77
80
|
\`\`\`
|
|
78
81
|
|
|
79
82
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
80
|
-
`;await
|
|
81
|
-
Cleaning up: Deleting directory ${
|
|
82
|
-
Process interrupted. Cleaning up...`)),await
|
|
83
|
+
`;await d(n,i)}else await g(n)};var Se=t=>{t.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").action(async e=>{await dt(e)})},dt=async t=>{pe(),l("Welcome to the Teispace Next.js App Creator!"),l("");let e=await se(t),r=te.resolve(process.cwd(),e.projectName);x(r)&&(console.error(G.red(`Error: Directory ${e.projectName} already exists.`)),process.exit(1));let s=D("Initializing project..."),n=async()=>{if(x(r)){s.stop(),console.log(G.yellow(`
|
|
84
|
+
Cleaning up: Deleting directory ${e.projectName}...`));try{await S(r),console.log(G.green("Cleanup successful."))}catch(o){console.error(G.red(`Failed to clean up directory ${e.projectName}:`),o)}}},i=async()=>{console.log(G.red(`
|
|
85
|
+
Process interrupted. Cleaning up...`)),await n(),process.exit(1)};process.on("SIGINT",i),process.on("SIGTERM",i);try{if(await ue(r),await de(r,e),await fe(r,e),s.text="Generating code...",await ge(r,e),await he(r,e),s.text="Setting up developer tools...",await ye(r,e),s.text="Initializing Git...",await ne(r),e.gitRemote&&await ae(r,e.gitRemote),s.text="Installing dependencies...",await le(r,e.packageManager),s.text="Formatting and Linting...",await Q(r,e.packageManager,"format"),await Q(r,e.packageManager,"lint:fix"),e.copyEnv){s.text="Creating .env file...";let o=te.join(r,".env.example"),c=te.join(r,".env");x(o)&&await(await import("node:fs/promises")).copyFile(o,c)}process.off("SIGINT",i),process.off("SIGTERM",i),s.succeed(G.green(`Project ${e.projectName} created successfully!`)),l(""),l("To get started:"),l(G.cyan(` cd ${e.projectName}`)),l(G.cyan(` ${e.packageManager==="npm"?"npm run dev":e.packageManager+" dev"}`)),l("")}catch(o){s.fail("Failed to create project."),console.error(o),await n(),process.exit(1)}};import E from"picocolors";import oe from"node:path";import ft from"enquirer";var{prompt:gt}=ft,Ce=async(t,e,r,s,n,i,o)=>{let c=[];t||c.push({type:"input",name:"featureName",message:"What is the feature name?",initial:"my-feature",validate:u=>/^[a-z0-9-]+$/.test(u)?!0:"Feature name must be lowercase and contain only alphanumeric characters and hyphens."}),e&&s===void 0&&n===void 0&&(c.push({type:"confirm",name:"createStore",message:"Generate Redux store for this feature?",initial:!0}),c.push({type:"confirm",name:"persistStore",message:"Enable persistence for this store?",initial:!1,skip(){return!this.state.answers.createStore}})),r&&r!=="none"&&i===void 0&&o===void 0&&(c.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),r==="both"&&c.push({type:"select",name:"selectedHttpClient",message:"Which HTTP client to use for the service?",choices:["fetch","axios"],initial:0,skip(){return!this.state.answers.createService}}));let m=c.length>0?await gt(c):{};return{featureName:t||m.featureName,hasRedux:e||!1,createStore:s===!0?!1:n!==void 0?!0:m.createStore||!1,persistStore:n==="persist"?!0:n==="no-persist"?!1:m.persistStore||!1,httpClient:r||"none",createService:i===!0?!1:o!==void 0?!0:m.createService||!1,selectedHttpClient:o||m.selectedHttpClient||(r==="both"?"fetch":r!=="none"?r:void 0)}};import{readFile as ht,access as re}from"node:fs/promises";import z from"node:path";var H=async t=>{let e=!1,r=!1,s=!1,n=!1;try{let i=z.join(t,"package.json"),o=await ht(i,"utf-8"),c=JSON.parse(o),m={...c.dependencies,...c.devDependencies};e=!!(m["@reduxjs/toolkit"]&&m["react-redux"]),r=!!m.axios,n=!!m["next-intl"];let u=z.join(t,"src","lib","utils","http","axios-client");try{await re(u),r=r&&!0}catch{r=!1}let $=z.join(t,"src","lib","utils","http","fetch-client");try{await re($),s=!0}catch{s=!1}let I;return r&&s?I="both":r?I="axios":s?I="fetch":I="none",{hasRedux:e,httpClient:I,hasI18n:n}}catch(i){throw new Error(`Failed to detect project setup: ${i}`)}},Ee=async(t,e,r=z.join("src","features"))=>{let s=z.join(t,r,e);try{return await re(s),!0}catch{return!1}};import{writeFile as j,mkdir as W}from"node:fs/promises";import w from"node:path";var ve=async t=>{let{featurePath:e}=t;await W(w.join(e,"components"),{recursive:!0}),await W(w.join(e,"hooks"),{recursive:!0}),await W(w.join(e,"types"),{recursive:!0}),t.createStore&&await W(w.join(e,"store"),{recursive:!0}),t.createService&&await W(w.join(e,"services"),{recursive:!0}),await xt(t),await yt(t),await St(t),await vt(t),t.createStore&&await Ct(t),t.createService&&t.httpClient&&await Et(t)},xt=async t=>{let{featureName:e,featurePath:r}=t,s=F(e),n=`use${s}`,i=`'use client';
|
|
86
|
+
import { ${n} } from '../hooks/${n}';
|
|
87
|
+
|
|
88
|
+
export function ${s}() {
|
|
89
|
+
const {} = ${n}();
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div>
|
|
93
|
+
<h2>${s} Component</h2>
|
|
94
|
+
{/* Add your component UI here */}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default ${s};
|
|
100
|
+
`;await j(w.join(r,"components",`${s}.tsx`),i)},yt=async t=>{let{featureName:e,featurePath:r,createStore:s}=t,n=F(e),i=`use${n}`,o;s?o=`'use client';
|
|
101
|
+
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
|
102
|
+
import { select${n}State, setLoading, setError } from '../store/${e}.selectors';
|
|
103
|
+
|
|
104
|
+
export const ${i} = () => {
|
|
105
|
+
const dispatch = useAppDispatch();
|
|
106
|
+
const state = useAppSelector(select${n}State);
|
|
107
|
+
|
|
108
|
+
const handleSetLoading = (loading: boolean) => {
|
|
109
|
+
dispatch(setLoading(loading));
|
|
110
|
+
console.log('Loading state updated:', loading);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleSetError = (error: string | null) => {
|
|
114
|
+
dispatch(setError(error));
|
|
115
|
+
console.log('Error state updated:', error);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
state,
|
|
120
|
+
setLoading: handleSetLoading,
|
|
121
|
+
setError: handleSetError,
|
|
122
|
+
} as const;
|
|
123
|
+
};
|
|
124
|
+
`:o=`'use client';
|
|
125
|
+
import { useState } from 'react';
|
|
126
|
+
|
|
127
|
+
export const ${i} = () => {
|
|
128
|
+
// Add your state and logic here
|
|
129
|
+
const [state, setState] = useState({});
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
state,
|
|
133
|
+
// Add your methods here
|
|
134
|
+
} as const;
|
|
135
|
+
};
|
|
136
|
+
`,await j(w.join(r,"hooks",`${i}.ts`),o)},St=async t=>{let{featureName:e,featurePath:r,createStore:s}=t,o=`export interface ${`${F(e)}State`} {
|
|
137
|
+
// Add your state properties here
|
|
138
|
+
${s?`loading: boolean;
|
|
139
|
+
error: string | null;`:"// example: value: string;"}
|
|
140
|
+
}
|
|
141
|
+
`;await j(w.join(r,"types",`${e}.types.ts`),o)},Ct=async t=>{let{featureName:e,featurePath:r,persistStore:s}=t,n=F(e),i=O(e),o=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
142
|
+
import { ${n}State } from '../types/${e}.types';
|
|
143
|
+
|
|
144
|
+
const initialState: ${n}State = {
|
|
145
|
+
loading: false,
|
|
146
|
+
error: null,
|
|
147
|
+
// Add your initial state here
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const ${i}Slice = createSlice({
|
|
151
|
+
name: '${i}',
|
|
152
|
+
initialState,
|
|
153
|
+
reducers: {
|
|
154
|
+
setLoading: (state, action: PayloadAction<boolean>) => {
|
|
155
|
+
state.loading = action.payload;
|
|
156
|
+
},
|
|
157
|
+
setError: (state, action: PayloadAction<string | null>) => {
|
|
158
|
+
state.error = action.payload;
|
|
159
|
+
},
|
|
160
|
+
resetState: (state) => {
|
|
161
|
+
state.loading = false;
|
|
162
|
+
state.error = null;
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
export const { setLoading, setError, resetState } = ${i}Slice.actions;
|
|
168
|
+
|
|
169
|
+
export const ${i}Reducer = ${i}Slice.reducer;
|
|
170
|
+
`;await j(w.join(r,"store",`${e}.slice.ts`),o);let c=`import { RootState } from '@/store/rootReducer';
|
|
171
|
+
|
|
172
|
+
export const select${n}State = (state: RootState) => state.${i};
|
|
173
|
+
export { setLoading, setError, resetState } from './${e}.slice';
|
|
174
|
+
`;if(await j(w.join(r,"store",`${e}.selectors.ts`),c),s){let u=`import { PersistConfig } from 'redux-persist';
|
|
175
|
+
import storage from 'redux-persist/lib/storage';
|
|
176
|
+
import { ${n}State } from '../types/${e}.types';
|
|
177
|
+
|
|
178
|
+
export const ${i}PersistConfig: PersistConfig<${n}State> = {
|
|
179
|
+
key: '${i}',
|
|
180
|
+
storage,
|
|
181
|
+
// whitelist: ['someField'], // Specify which fields to persist
|
|
182
|
+
};
|
|
183
|
+
`;await j(w.join(r,"store","persist.ts"),u)}let m=`export * from './${e}.slice';
|
|
184
|
+
export * from './${e}.selectors';${s?`
|
|
185
|
+
export * from './persist';`:""}
|
|
186
|
+
`;await j(w.join(r,"store","index.ts"),m)},Et=async t=>{let{featureName:e,featurePath:r,httpClient:s}=t,n=O(e),i;s==="axios"?i=`import { axiosClient } from '@/lib/utils/http';
|
|
187
|
+
|
|
188
|
+
export const ${n}Service = {
|
|
189
|
+
// Add your API methods here
|
|
190
|
+
// Example:
|
|
191
|
+
// getAll: async () => {
|
|
192
|
+
// const result = await axiosClient.get<YourType[]>('/${e}');
|
|
193
|
+
// if (result.isErr()) throw result.error;
|
|
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
|
+
// },
|
|
220
|
+
};
|
|
221
|
+
`:i=`import { fetchClient } from '@/lib/utils/http';
|
|
222
|
+
|
|
223
|
+
export const ${n}Service = {
|
|
224
|
+
// Add your API methods here
|
|
225
|
+
// Example:
|
|
226
|
+
// getAll: async () => {
|
|
227
|
+
// const result = await fetchClient.get<YourType[]>('/${e}');
|
|
228
|
+
// if (result.isErr()) throw result.error;
|
|
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
|
+
// },
|
|
255
|
+
};
|
|
256
|
+
`,await j(w.join(r,"services",`${e}.service.ts`),i)},vt=async t=>{let{featureName:e,featurePath:r,createStore:s,createService:n}=t,i=F(e),o=`export { default as ${i} } from './components/${i}';
|
|
257
|
+
export { use${i} } from './hooks/use${i}';
|
|
258
|
+
export * from './types/${e}.types';${s?`
|
|
259
|
+
export * from './store';`:""}${n?`
|
|
260
|
+
export * from './services/${e}.service';`:""}
|
|
261
|
+
`;await j(w.join(r,"index.ts"),o)};import{readFile as Pe,writeFile as we}from"node:fs/promises";import ie from"node:path";var Te=async(t,e,r,s=ie.join("src","features"))=>{let n=ie.join(t,"src","store","rootReducer.ts");try{let i=await Pe(n,"utf-8"),o=O(e),c=`${o}Reducer`,m=r?`${o}PersistConfig`:"",u=s.replace(/^src\//,"@/"),$=r?`import { ${c}, ${m} } from '${u}/${e}/store';`:`import { ${c} } from '${u}/${e}/store';`,I=/import\s+.*\s+from\s+['"].*['"];?\n/g,N=i.match(I);if(N&&N.length>0){let R=N[N.length-1],_=i.lastIndexOf(R);i=i.slice(0,_+R.length)+$+`
|
|
262
|
+
`+i.slice(_+R.length)}else i=$+`
|
|
263
|
+
`+i;let P=/combineReducers\(\{([^}]*)\}\)/s,k=i.match(P);if(k){let R=k[1],_=r?`
|
|
264
|
+
${o}: persistReducer(${m}, ${c}),`:`
|
|
265
|
+
${o}: ${c},`,q=R.trimEnd()+_;i=i.replace(P,`combineReducers({${q}
|
|
266
|
+
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await we(n,i)}catch(i){throw new Error(`Failed to register feature in rootReducer: ${i}`)}},Ie=async(t,e,r,s)=>{let n=ie.join(t,"src","store","rootReducer.ts");try{let i=await Pe(n,"utf-8"),o=O(e),c=`${o}Reducer`,m=r?`${o}PersistConfig`:"",u=s.replace(/^src\//,"@/"),$=r?`import { ${c}, ${m} } from '${u}/${e}';`:`import { ${c} } from '${u}/${e}';`,I=/import\s+.*\s+from\s+['"].*['"];?\n/g,N=i.match(I);if(N&&N.length>0){let R=N[N.length-1],_=i.lastIndexOf(R);i=i.slice(0,_+R.length)+$+`
|
|
267
|
+
`+i.slice(_+R.length)}else i=$+`
|
|
268
|
+
`+i;let P=/combineReducers\(\{([^}]*)\}\)/s,k=i.match(P);if(k){let R=k[1],_=r?`
|
|
269
|
+
${o}: persistReducer(${m}, ${c}),`:`
|
|
270
|
+
${o}: ${c},`,q=R.trimEnd()+_;i=i.replace(P,`combineReducers({${q}
|
|
271
|
+
})`)}else throw new Error("Could not find combineReducers in rootReducer.ts");await we(n,i)}catch(i){throw new Error(`Failed to register slice in rootReducer: ${i}`)}};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,r)=>{try{let s=process.cwd();r.store&&!["persist","no-persist"].includes(r.store)&&(C("Invalid --store option. Use: persist or no-persist"),process.exit(1)),r.service&&!["axios","fetch"].includes(r.service)&&(C("Invalid --service option. Use: axios or fetch"),process.exit(1)),r.skipStore&&r.store&&(C("Cannot use --skip-store and --store together"),process.exit(1)),r.skipService&&r.service&&(C("Cannot use --skip-service and --service together"),process.exit(1)),l(E.cyan(`
|
|
272
|
+
\u{1F3AF} Feature Generator
|
|
273
|
+
`)),h.start("Detecting project setup...");let n=await H(s);h.succeed("Project setup detected"),l(E.dim(` Redux: ${n.hasRedux?"\u2713":"\u2717"}`)),l(E.dim(` HTTP Client: ${n.httpClient}`)),l(E.dim(` i18n: ${n.hasI18n?"\u2713":"\u2717"}
|
|
274
|
+
`));let i=await Ce(e,n.hasRedux,n.httpClient,r.skipStore,r.store,r.skipService,r.service),o=r.path||oe.join("src","features"),c=oe.join(s,o,i.featureName);await Ee(s,i.featureName,o)&&(C(`Feature '${i.featureName}' already exists at ${o}!`),process.exit(1)),h.start("Generating feature files..."),await ve({featureName:i.featureName,featurePath:c,createStore:i.createStore,persistStore:i.persistStore,createService:i.createService,httpClient:i.selectedHttpClient}),h.succeed("Feature files generated"),i.createStore&&n.hasRedux&&(h.start("Registering feature in rootReducer..."),await Te(s,i.featureName,i.persistStore,o),h.succeed("Feature registered in rootReducer"));let u=oe.join(o,i.featureName);l(E.green(`
|
|
275
|
+
\u2728 Feature '${i.featureName}' created successfully!
|
|
276
|
+
`)),l(E.dim("Generated files:")),l(E.dim(` \u{1F4C2} ${u}/`)),l(E.dim(" \u251C\u2500\u2500 components/")),l(E.dim(" \u251C\u2500\u2500 hooks/")),l(E.dim(" \u251C\u2500\u2500 types/")),i.createStore&&l(E.dim(" \u251C\u2500\u2500 store/")),i.createService&&l(E.dim(" \u251C\u2500\u2500 services/")),l(E.dim(` \u2514\u2500\u2500 index.ts
|
|
277
|
+
`)),l(E.cyan("Next steps:"));let $=o.replace(/^src\//,"@/");l(E.dim(` 1. Import and use the feature: import { ${i.featureName} } from '${$}/${i.featureName}'`)),i.createStore&&l(E.dim(` 2. Customize your Redux slice in: ${u}/store/`)),i.createService&&l(E.dim(` 3. Add API methods in: ${u}/services/${i.featureName}.service.ts`)),l("")}catch(s){h.fail("Feature generation failed"),C(`${s}`),process.exit(1)}})};import T from"picocolors";import L from"node:path";import{existsSync as _t}from"node:fs";import{mkdir as jt}from"node:fs/promises";import Pt from"enquirer";var{prompt:wt}=Pt,$e=async(t,e,r)=>{let s=[];t||s.push({type:"input",name:"sliceName",message:"What is the slice name?",initial:"my-slice",validate:i=>/^[a-z0-9-]+$/.test(i)?!0:"Slice name must be lowercase and contain only alphanumeric characters and hyphens."}),e===void 0&&r===void 0&&s.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let n=s.length>0?await wt(s):{};return{sliceName:t||n.sliceName,persistSlice:e===!0?!0:r===!1?!1:n.persistSlice||!1}};import{writeFile as K,mkdir as Tt}from"node:fs/promises";import V from"node:path";var Re=async t=>{let{sliceName:e,slicePath:r,persistSlice:s}=t;await Tt(r,{recursive:!0});let n=F(e),i=O(e);await It(e,r,n),await Nt(e,r,n,i),await $t(e,r,n,i),s&&await Rt(e,r,n,i),await Ot(e,r,s)},It=async(t,e,r)=>{let s=`export interface ${r}State {
|
|
278
|
+
loading: boolean;
|
|
279
|
+
error: string | null;
|
|
280
|
+
// Add your state properties here
|
|
281
|
+
}
|
|
282
|
+
`;await K(V.join(e,`${t}.types.ts`),s)},Nt=async(t,e,r,s)=>{let n=`import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
283
|
+
import { ${r}State } from './${t}.types';
|
|
284
|
+
|
|
285
|
+
const initialState: ${r}State = {
|
|
286
|
+
loading: false,
|
|
287
|
+
error: null,
|
|
288
|
+
// Add your initial state here
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export const ${s}Slice = createSlice({
|
|
292
|
+
name: '${s}',
|
|
293
|
+
initialState,
|
|
294
|
+
reducers: {
|
|
295
|
+
setLoading: (state, action: PayloadAction<boolean>) => {
|
|
296
|
+
state.loading = action.payload;
|
|
297
|
+
},
|
|
298
|
+
setError: (state, action: PayloadAction<string | null>) => {
|
|
299
|
+
state.error = action.payload;
|
|
300
|
+
},
|
|
301
|
+
resetState: (state) => {
|
|
302
|
+
state.loading = false;
|
|
303
|
+
state.error = null;
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
export const { setLoading, setError, resetState } = ${s}Slice.actions;
|
|
309
|
+
|
|
310
|
+
export const ${s}Reducer = ${s}Slice.reducer;
|
|
311
|
+
`;await K(V.join(e,`${t}.slice.ts`),n)},$t=async(t,e,r,s)=>{let n=`import { RootState } from '@/store/rootReducer';
|
|
312
|
+
|
|
313
|
+
export const select${r}State = (state: RootState) => state.${s};
|
|
314
|
+
export { setLoading, setError, resetState } from './${t}.slice';
|
|
315
|
+
`;await K(V.join(e,`${t}.selectors.ts`),n)},Rt=async(t,e,r,s)=>{let n=`import { PersistConfig } from 'redux-persist';
|
|
316
|
+
import storage from 'redux-persist/lib/storage';
|
|
317
|
+
import { ${r}State } from './${t}.types';
|
|
318
|
+
|
|
319
|
+
export const ${s}PersistConfig: PersistConfig<${r}State> = {
|
|
320
|
+
key: '${s}',
|
|
321
|
+
storage,
|
|
322
|
+
// whitelist: ['someField'], // Specify which fields to persist
|
|
323
|
+
};
|
|
324
|
+
`;await K(V.join(e,"persist.ts"),n)},Ot=async(t,e,r)=>{let s=`export * from './${t}.slice';
|
|
325
|
+
export * from './${t}.selectors';
|
|
326
|
+
export * from './${t}.types';${r?`
|
|
327
|
+
export * from './persist';`:""}
|
|
328
|
+
`;await K(V.join(e,"index.ts"),s)};import{access as bt}from"node:fs/promises";import Oe from"node:path";var be=async(t,e,r=Oe.join("src","store","slices"))=>{let s=Oe.join(t,r,e);try{return await bt(s),!0}catch{return!1}};var _e=t=>{t.command("slice [name]").description("Generate a Redux slice").option("--path <path>","Custom path for slice generation (default: create new feature)").option("--persist","Enable persistence for this slice").option("--no-persist","Disable persistence for this slice").action(async(e,r)=>{try{let s=process.cwd();r.persist&&r.noPersist===!0&&(C("Cannot use --persist and --no-persist together"),process.exit(1)),l(T.cyan(`
|
|
329
|
+
\u{1F527} Slice Generator
|
|
330
|
+
`)),h.start("Detecting project setup...");let n=await H(s);h.succeed("Project setup detected"),n.hasRedux||(h.fail("Redux is not setup in this project"),C("Please install @reduxjs/toolkit and react-redux first"),l(T.dim(`
|
|
331
|
+
Run: npm install @reduxjs/toolkit react-redux
|
|
332
|
+
`)),process.exit(1)),l(T.dim(` Redux: \u2713
|
|
333
|
+
`));let i=await $e(e,r.persist,r.noPersist===!0?!1:void 0),o,c,m;if(r.path){let P=r.path.replace(/^src\//,"");P.startsWith("features/")?(c=P.split("/")[1],o=L.join("src","features",c,"store"),m=L.join(s,o,i.sliceName)):(o=L.join("src",P),c=P.split("/")[0],m=L.join(s,o,i.sliceName))}else c=i.sliceName,o=L.join("src","features",c,"store"),m=L.join(s,o,i.sliceName);let u=L.join(s,o);_t(u)||await jt(u,{recursive:!0}),await be(s,i.sliceName,o)&&(C(`Slice '${i.sliceName}' already exists at ${o}!`),process.exit(1)),h.start("Generating slice files..."),await Re({sliceName:i.sliceName,slicePath:m,persistSlice:i.persistSlice}),h.succeed("Slice files generated"),h.start("Registering slice in rootReducer..."),await Ie(s,i.sliceName,i.persistSlice,o),h.succeed("Slice registered in rootReducer");let I=L.join(o,i.sliceName);l(T.green(`
|
|
334
|
+
\u2728 Slice '${i.sliceName}' created successfully!
|
|
335
|
+
`)),l(T.dim("Generated files:")),l(T.dim(` \u{1F4C2} ${I}/`)),l(T.dim(` \u251C\u2500\u2500 ${i.sliceName}.slice.ts`)),l(T.dim(` \u251C\u2500\u2500 ${i.sliceName}.selectors.ts`)),i.persistSlice&&l(T.dim(" \u251C\u2500\u2500 persist.ts")),l(T.dim(` \u251C\u2500\u2500 ${i.sliceName}.types.ts`)),l(T.dim(` \u2514\u2500\u2500 index.ts
|
|
336
|
+
`)),l(T.cyan("Next steps:"));let N=o.replace(/^src\//,"@/");l(T.dim(` 1. Import actions: import { setLoading, setError } from '${N}/${i.sliceName}'`)),l(T.dim(" 2. Use in component: dispatch(setLoading(true))")),l("")}catch(s){h.fail("Slice generation failed"),C(`${s}`),process.exit(1)}})};import A from"picocolors";import U from"node:path";import{existsSync as kt}from"node:fs";import{mkdir as Mt}from"node:fs/promises";import je from"enquirer";var Ae=async(t,e,r,s)=>{let n=t||(await je.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,i;return e!==void 0?i="axios":r!==void 0?i="fetch":s==="axios"?i="axios":s==="fetch"?i="fetch":s==="both"?i=(await je.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:i="axios",{serviceName:n,httpClient:i}};import{writeFile as At}from"node:fs/promises";import Dt from"node:path";var De=async t=>{await Ft(t)},Ft=async t=>{let{serviceName:e,servicePath:r,httpClient:s}=t,n=O(e),i;s==="axios"?i=`import { axiosClient } from '@/lib/utils/http';
|
|
337
|
+
|
|
338
|
+
export const ${n}Service = {
|
|
339
|
+
// Add your API methods here
|
|
340
|
+
// Example:
|
|
341
|
+
// getAll: async () => {
|
|
342
|
+
// const result = await axiosClient.get<YourType[]>('/${e}');
|
|
343
|
+
// if (result.isErr()) throw result.error;
|
|
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
|
+
// },
|
|
370
|
+
};
|
|
371
|
+
`:i=`import { fetchClient } from '@/lib/utils/http';
|
|
372
|
+
|
|
373
|
+
export const ${n}Service = {
|
|
374
|
+
// Add your API methods here
|
|
375
|
+
// Example:
|
|
376
|
+
// getAll: async () => {
|
|
377
|
+
// const result = await fetchClient.get<YourType[]>('/${e}');
|
|
378
|
+
// if (result.isErr()) throw result.error;
|
|
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
|
+
// },
|
|
405
|
+
};
|
|
406
|
+
`;let o=`${e}.service.ts`;await At(Dt.join(r,o),i)};import{existsSync as Gt}from"node:fs";import Lt from"node:path";var Fe=async(t,e,r)=>{let s=Lt.join(t,r,`${e}.service.ts`);return Gt(s)};var Ge=t=>{t.command("service [name]").description("Generate an API service").option("--path <path>","Custom path for service generation (default: create new feature)").option("--axios","Use Axios HTTP client").option("--fetch","Use Fetch HTTP client").action(async(e,r)=>{try{let s=process.cwd();r.axios&&r.fetch&&(C("Cannot use --axios and --fetch together"),process.exit(1)),l(A.cyan(`
|
|
407
|
+
\u{1F527} Service Generator
|
|
408
|
+
`)),h.start("Detecting project setup...");let n=await H(s);h.succeed("Project setup detected"),n.httpClient==="none"&&(h.fail("No HTTP client is setup in this project"),C("Please setup either AxiosClient or FetchClient first"),l(A.dim(`
|
|
409
|
+
Check: lib/utils/http/axios-client or lib/utils/http/fetch-client
|
|
410
|
+
`)),process.exit(1));let i=[];(n.httpClient==="axios"||n.httpClient==="both")&&i.push("Axios \u2713"),(n.httpClient==="fetch"||n.httpClient==="both")&&i.push("Fetch \u2713"),l(A.dim(` HTTP Clients: ${i.join(", ")}
|
|
411
|
+
`));let o=await Ae(e,r.axios,r.fetch,n.httpClient),c,m,u;if(r.path){let P=r.path.replace(/^src\//,"");P.startsWith("features/")?(m=P.split("/")[1],c=U.join("src","features",m,"services"),u=U.join(s,c)):(c=U.join("src",P),m=P.split("/")[0],u=U.join(s,c))}else m=o.serviceName,c=U.join("src","features",m,"services"),u=U.join(s,c);kt(u)||await Mt(u,{recursive:!0}),await Fe(s,o.serviceName,c)&&(C(`Service '${o.serviceName}' already exists at ${c}!`),process.exit(1)),h.start("Generating service files..."),await De({serviceName:o.serviceName,servicePath:u,httpClient:o.httpClient}),h.succeed("Service files generated");let I=U.join(c,`${o.serviceName}.service.ts`);l(A.green(`
|
|
412
|
+
\u2728 Service '${o.serviceName}' created successfully!
|
|
413
|
+
`)),l(A.dim("Generated files:")),l(A.dim(` \u{1F4C4} ${I}
|
|
414
|
+
`)),l(A.cyan("Next steps:"));let N=c.replace(/^src\//,"@/");l(A.dim(` 1. Import service: import { ${o.serviceName}Service } from '${N}/${o.serviceName}.service'`)),l(A.dim(` 2. Use in component: const data = await ${o.serviceName}Service.getAll()`)),l("")}catch(s){h.fail("Service generation failed"),C(`${s}`),process.exit(1)}})};var Le=t=>{Se(t),Ne(t),_e(t),Ge(t)};async function Ht(){me({logger:e=>J(e)});let t=new Ut;t.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),Le(t),t.parse()}Ht().catch(t=>{let e=t&&typeof t=="object"&&"message"in t?t.message:String(t);J(`Unexpected error: ${e}`)});
|
|
83
415
|
//# sourceMappingURL=index.js.map
|