@teispace/next-maker 1.19.2 → 1.20.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 +278 -271
- package/dist/index.js.map +4 -4
- package/dist/src/commands/favicon.d.ts +3 -0
- package/dist/src/commands/favicon.d.ts.map +1 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/prompts/favicon.prompt.d.ts +7 -0
- package/dist/src/prompts/favicon.prompt.d.ts.map +1 -0
- package/dist/src/services/favicon/css-colors.d.ts +8 -0
- package/dist/src/services/favicon/css-colors.d.ts.map +1 -0
- package/dist/src/services/favicon/detect.d.ts +16 -0
- package/dist/src/services/favicon/detect.d.ts.map +1 -0
- package/dist/src/services/favicon/encoders.d.ts +23 -0
- package/dist/src/services/favicon/encoders.d.ts.map +1 -0
- package/dist/src/services/favicon/index.d.ts +7 -0
- package/dist/src/services/favicon/index.d.ts.map +1 -0
- package/dist/src/services/favicon/manifest.d.ts +25 -0
- package/dist/src/services/favicon/manifest.d.ts.map +1 -0
- package/dist/src/services/favicon/pipeline.d.ts +3 -0
- package/dist/src/services/favicon/pipeline.d.ts.map +1 -0
- package/dist/src/services/favicon/shapes.d.ts +11 -0
- package/dist/src/services/favicon/shapes.d.ts.map +1 -0
- package/dist/src/services/favicon/types.d.ts +32 -0
- package/dist/src/services/favicon/types.d.ts.map +1 -0
- package/dist/src/services/favicon/validate.d.ts +11 -0
- package/dist/src/services/favicon/validate.d.ts.map +1 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`),
|
|
4
|
-
`),await
|
|
5
|
-
`,await
|
|
6
|
-
`),
|
|
7
|
-
`),await
|
|
8
|
-
`,await
|
|
2
|
+
var Xi=Object.defineProperty;var be=(e,t)=>()=>(e&&(t=e(e=0)),t);var Nt=(e,t)=>{for(var r in t)Xi(e,r,{get:t[r],enumerable:!0})};import{existsSync as kt}from"node:fs";import ye from"node:fs/promises";import Hr from"node:path";var f,g,j,T,w,F,m,P=be(()=>{"use strict";f=async e=>ye.readFile(e,"utf-8"),g=async(e,t)=>{await ye.mkdir(Hr.dirname(e),{recursive:!0}),await ye.writeFile(e,t,"utf-8")},j=async(e,t)=>{await ye.mkdir(Hr.dirname(t),{recursive:!0}),await ye.copyFile(e,t)},T=async e=>{kt(e)&&await ye.unlink(e)},w=async e=>{kt(e)&&await ye.rm(e,{recursive:!0,force:!0})},F=async(e,t)=>{let r=await f(e),n=JSON.parse(r),o=t(n);await g(e,JSON.stringify(o,null,2))},m=e=>kt(e)});var qr={};Nt(qr,{PROJECT_PATHS:()=>c});var c,S=be(()=>{"use strict";c={NEXT_CONFIG:"next.config.ts",POSTCSS_CONFIG:"postcss.config.mjs",BIOME_CONFIG:"biome.json",VITEST_CONFIG:"vitest.config.ts",TEST_DIR:"test",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",AGENTS_MD:"AGENTS.md",CLAUDE_MD:"CLAUDE.md",SRC:"src",APP:"src/app",COMPONENTS:"src/components",LIB:"src/lib",PROVIDERS:"src/providers",STYLES:"src/styles",TYPES:"src/types",UTILS:"src/lib/utils",HOOKS:"src/hooks",SERVICES:"src/services",STORE:"src/store",I18N:"src/i18n",GLOBALS_CSS:"src/styles/globals.css",ROOT_LAYOUT:"src/app/layout.tsx",ROOT_PAGE:"src/app/page.tsx",ROOT_PROVIDER:"src/providers/RootProvider.tsx",PROVIDERS_INDEX:"src/providers/index.ts",COMPONENTS_INDEX:"src/components/index.ts",TYPES_INDEX:"src/types/index.ts",UTILS_INDEX:"src/lib/utils/index.ts",CONFIG_INDEX:"src/lib/config/index.ts",CONSTANTS:"src/lib/config/constants.ts",APP_LOCALES:"src/lib/config/app-locales.ts",MIDDLEWARE:"src/middleware.ts",PROXY:"src/proxy.ts",I18N_TYPES:"src/types/i18n.ts",HTTP_UTILS:"src/lib/utils/http",AXIOS_CLIENT:"src/lib/utils/http/axios-client",FETCH_CLIENT:"src/lib/utils/http/fetch-client",AXIOS_CLIENT_FILE:"src/lib/utils/http/axios-client/index.ts",FETCH_CLIENT_FILE:"src/lib/utils/http/fetch-client/index.ts",CLIENT_UTILS:"src/lib/utils/http/client-utils.ts",APP_APIS:"src/lib/config/app-apis.ts",STORAGE_SERVICE:"src/services/storage",COUNTER_FEATURE:"src/features/counter",I18N_DIR:"src/i18n",LOCALE_DIR:"src/app/[locale]",ERRORS_DIR:"src/lib/errors",UTILITY_TYPES_DIR:"src/types/utility",COMMON_TYPES_DIR:"src/types/common",HTTP_TYPES:"src/types/common/http.types.ts",GITHUB_DIR:".github",HUSKY_DIR:".husky",STORE_PROVIDER:"src/providers/StoreProvider.tsx",THEME_PROVIDER:"src/providers/CustomThemeProvider.tsx",COUNTER_COMPONENT:"src/features/counter/components/Counter.tsx",LOCALE_PAGE:"src/app/[locale]/page.tsx",COMMITLINT_CONFIG:"commitlint.config.mjs",LINTSTAGED_RC:".lintstagedrc.mjs",CZRC:".czrc",DOCKERIGNORE:".dockerignore",DOCKERFILE:"Dockerfile",DOCKER_COMPOSE:"docker-compose.yml",GITHUB_WORKFLOWS:".github/workflows",GITHUB_ISSUE_TEMPLATE:"ISSUE_TEMPLATE",GITHUB_PR_TEMPLATE:"PULL_REQUEST_TEMPLATE.md",CODE_OF_CONDUCT:"CODE_OF_CONDUCT.md",CONTRIBUTING:"CONTRIBUTING.md",SECURITY:"SECURITY.md",SCRIPTS_DIR:"scripts",DOCS_DIR:"docs",CLAUDE_DIR:".claude",VSCODE_DIR:".vscode"}});var Kr={};Nt(Kr,{cleanupHttpTypes:()=>Re,isFileUsed:()=>Es,isStringUsed:()=>bs,migrateClientUsages:()=>Mt,removeHttpExports:()=>Gt,updateConfigIndex:()=>Lt,updateHttpIndex:()=>_t,updateTypesIndex:()=>Dt,updateUtilsIndex:()=>jt});import{exec as Cs}from"node:child_process";import D from"node:path";import{promisify as Ts}from"node:util";var Ft,_t,jt,Dt,Lt,Re,Mt,Gt,Es,bs,dt=be(()=>{"use strict";S();P();Ft=Ts(Cs),_t=async(e,t)=>{let r=D.join(e,c.HTTP_UTILS,"index.ts");if(m(r)){let n=await f(r);n=n.replace(/export .* from '\.\/axios-client';?\n?/g,""),n=n.replace(/export .* from '\.\/fetch-client';?\n?/g,""),t.includes("fetch")&&!n.includes("fetch-client")&&(n+=`export * from './fetch-client';
|
|
3
|
+
`),t.includes("axios")&&!n.includes("axios-client")&&(n+=`export * from './axios-client';
|
|
4
|
+
`),await g(r,n)}},jt=async e=>{let t=D.join(e,c.UTILS_INDEX);if(m(t)){let r=await f(t);r.includes("./http")||(r+=`export * from './http';
|
|
5
|
+
`,await g(t,r))}},Dt=async e=>{let t=D.join(e,c.TYPES_INDEX);if(m(t)){let r=await f(t);r.includes("./common")||(r+=`export * from './common';
|
|
6
|
+
`),r.includes("./utility")||(r+=`export * from './utility';
|
|
7
|
+
`),await g(t,r)}},Lt=async e=>{let t=D.join(e,c.CONFIG_INDEX);if(m(t)){let r=await f(t);r.includes("./app-apis")||(r+=`export * from './app-apis';
|
|
8
|
+
`,await g(t,r))}},Re=async(e,t)=>{let r=D.join(e,c.HTTP_TYPES);if(m(r)){let n=await f(r);t.includes("axios")||(n=n.replace(/declare module 'axios'\s*\{\s*export interface AxiosRequestConfig\s*\{[\s\S]*?\}\s*\}/g,""),n=`${n.replace(/\n\s*\n/g,`
|
|
9
9
|
|
|
10
10
|
`).trim()}
|
|
11
|
-
`,await
|
|
12
|
-
`).filter(h=>h);for(let h of
|
|
13
|
-
`).filter(d=>{let[
|
|
14
|
-
`).filter(d=>{let[g]=d.split(":"),h=F.resolve(e,g);return!t.some(x=>!!(h===x||h.startsWith(x+F.sep)))}).length>0:!1}catch(s){return console.warn(`Warning: Failed to check usage for string ${r}:`,s),!0}}});import{existsSync as vs}from"node:fs";import{access as Ss}from"node:fs/promises";import tn from"node:path";var ie,at,rn=Pe(()=>{"use strict";ie=async(e,r,t)=>{try{return await Ss(tn.join(e,t,r)),!0}catch{return!1}},at=(e,r,t)=>vs(tn.join(e,r,t))});import{access as Ft,readFile as ws}from"node:fs/promises";import ct from"node:path";var I,nn=Pe(()=>{"use strict";I=async e=>{try{let r=ct.join(e,"package.json"),t=await ws(r,"utf-8"),n=JSON.parse(t),o={...n.dependencies,...n.devDependencies},i=!!(o["@reduxjs/toolkit"]&&o["react-redux"]),s=!!o["next-intl"],a=!!o.axios,p=!1,d=ct.join(e,"src","lib","utils","http","axios-client");try{await Ft(d)}catch{a=!1}let g=ct.join(e,"src","lib","utils","http","fetch-client");try{await Ft(g),p=!0}catch{p=!1}let h;a&&p?h="both":a?h="axios":p?h="fetch":h="none";let x=!!o.vitest;if(!x)try{await Ft(ct.join(e,"vitest.config.ts")),x=!0}catch{}return{hasRedux:i,httpClient:h,hasI18n:s,hasTests:x}}catch(r){throw new Error(`Failed to detect project setup: ${r}`,{cause:r})}}});var Ne={};St(Ne,{detectProjectSetup:()=>I,directoryExists:()=>ie,fileExistsAt:()=>at});var L=Pe(()=>{"use strict";rn();nn()});import{Command as Kc}from"commander";import Ot from"node:path";import V from"picocolors";function Cr(e){let{logger:r=s=>console.error(s),exitOnCancel:t=process.env.NODE_ENV!=="test"}=e??{},n=()=>{console.log(""),console.log(""),r("Setup cancelled by user"),console.log(""),t&&process.exit(0)},o=s=>{if(s!==null&&typeof s=="object"&&"code"in s&&s.code==="ERR_USE_AFTER_CLOSE"){n();return}if(s instanceof Error){r(`Uncaught exception: ${s.message}`);return}r(`Uncaught exception: ${String(s)}`)},i=s=>{if(s instanceof Error){r(`Unhandled promise rejection: ${s.message}`);return}r(`Unhandled promise rejection: ${String(s)}`)};return process.on("SIGINT",n),process.on("SIGTERM",n),process.on("uncaughtException",o),process.on("unhandledRejection",i),()=>{process.off("SIGINT",n),process.off("SIGTERM",n),process.off("uncaughtException",o),process.off("unhandledRejection",i)}}import q from"picocolors";var gi={reset:e=>e,red:q.red,green:q.green,yellow:q.yellow,blue:q.blue,cyan:q.cyan,magenta:q.magenta,white:q.white,gray:q.gray,bright:q.bold,dim:q.dim};function me(e,r="reset"){let t=gi[r]??(n=>n);console.log(t(e))}function nt(e){me(`\u2716 ${e}`,"red")}var v=nt;function l(e){me(e)}function Tr(){console.log(""),me("\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"),me("\u2551 \u2551","cyan"),me("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),me("\u2551 \u2551","cyan"),me("\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("")}import hi from"ora";function R(e="",r){let t=hi({text:e,...r});return t.start(),t}var yi=e=>e.charAt(0).toUpperCase()+e.slice(1),A=e=>e.replace(/-([a-z])/g,(r,t)=>t.toUpperCase()),$=e=>yi(A(e));import xi from"ora";var y=xi();P();import{exec as Pi}from"node:child_process";import{promisify as vi}from"node:util";var Q=vi(Pi),Rr=async(e,r,t)=>{try{if(await Q("git init",{cwd:e}),await Q("git add .",{cwd:e}),await Q('git commit -m "Initial commit from @teispace/next-maker"',{cwd:e}),r&&(await Q(`git remote add origin ${r}`,{cwd:e}),t)){await Q("git fetch origin",{cwd:e});let n="main";try{await Q("git show-branch origin/main",{cwd:e})}catch{try{await Q("git show-branch origin/master",{cwd:e}),n="master"}catch{n="main"}}await Q(`git merge origin/${n} --allow-unrelated-histories -X ours`,{cwd:e}),await Q(`git push origin HEAD:${n}`,{cwd:e})}}catch(n){console.warn("Failed to initialize git repository",n)}};import{exec as Si}from"node:child_process";import{promisify as wi}from"node:util";var Re=wi(Si),$r=async(e,r)=>{let t=`${r} install`;try{await Re(t,{cwd:e})}catch(n){throw new Error(`Failed to install dependencies with ${r}: ${n}`,{cause:n})}},U=async(e,r,t)=>{let n=r==="npm"?`${r} run ${t}`:`${r} ${t}`;try{await Re(n,{cwd:e})}catch(o){console.warn(`Warning: Failed to run script '${t}': ${o}`)}},Ci=()=>{let e=process.env.npm_config_user_agent;if(e){if(e.startsWith("yarn"))return"yarn";if(e.startsWith("pnpm"))return"pnpm";if(e.startsWith("bun"))return"bun"}return"npm"},O=async e=>{let{existsSync:r}=await import("node:fs"),t=await import("node:path");return r(t.join(e,"pnpm-lock.yaml"))?"pnpm":r(t.join(e,"yarn.lock"))?"yarn":r(t.join(e,"bun.lockb"))?"bun":r(t.join(e,"package-lock.json"))?"npm":Ci()},Ti=async(e,r,t)=>{if(t.length===0)return;let o=`${br(r)} ${t.join(" ")}`;try{await Re(o,{cwd:e})}catch(i){throw new Error(`Failed to install packages with ${r}: ${i}`,{cause:i})}},br=e=>{switch(e){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}},z=async(e,r)=>{let t=await O(e);await Ti(e,t,[r])},Ei=e=>{switch(e){case"npm":return"--save-dev";case"yarn":case"pnpm":case"bun":return"-D";default:return"--save-dev"}},ue=async(e,r,t)=>{if(t.length===0)return;let n=br(r),o=Ei(r),i=`${n} ${o} ${t.join(" ")}`;try{await Re(i,{cwd:e})}catch(s){throw new Error(`Failed to install dev packages with ${r}: ${s}`,{cause:s})}},ot=async(e,r)=>{let t=await O(e);await ue(e,t,[r])},Ct=async(e,r,t)=>{if(t.length===0)return;let o=`${Ri(r)} ${t.join(" ")}`;try{await Re(o,{cwd:e})}catch(i){throw new Error(`Failed to uninstall packages with ${r}: ${i}`,{cause:i})}},Ri=e=>{switch(e){case"npm":return"npm uninstall";case"yarn":return"yarn remove";case"pnpm":return"pnpm remove";case"bun":return"bun remove";default:return"npm uninstall"}},Tt=async(e,r)=>{let t=await O(e);await Ct(e,t,[r])};import $i from"enquirer";var bi=/^[a-z0-9-_]+$/,Ni=/^\d+\.\d+\.\d+$/,Ii=e=>bi.test(e),Ai=e=>Ni.test(e),Nr=(e,r={})=>{let t=r.projectName??e??"my-app";if(!Ii(t))throw new Error(`Invalid project name "${t}". Use lowercase letters, digits, hyphens, and underscores only.`);let n=r.version??"0.1.0";if(!Ai(n))throw new Error(`Invalid version "${n}". Expected semver (e.g. 0.1.0).`);let o=r.author??"Teispace",i=r.company??o;return{projectName:t,description:r.description??"A Next.js application",author:o,version:n,packageManager:r.packageManager??"yarn",gitRemote:r.gitRemote??"",pushToRemote:r.pushToRemote??!1,gitIssues:r.gitIssues??"",gitHomepage:r.gitHomepage??"",httpClient:r.httpClient??"fetch",reactSecureStorage:r.reactSecureStorage??!0,email:r.email??"support@example.com",company:i,keepTemplates:r.keepTemplates??!1,darkMode:r.darkMode??!0,redux:r.redux??!0,i18n:r.i18n??!0,communityFiles:r.communityFiles??[],readme:r.readme??!0,docker:r.docker??!1,containerName:r.containerName,imageName:r.imageName,imageTag:r.imageTag,ci:r.ci??!1,preCommitHooks:r.preCommitHooks??!0,commitizen:r.commitizen??!0,copyEnv:r.copyEnv??!0,tests:r.tests??!0,reactCompiler:r.reactCompiler??!0,bundleAnalyzer:r.bundleAnalyzer??!1}},{prompt:ki}=$i,Ir=async e=>{let r=await ki([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,validate:t=>/^[a-z0-9-_]+$/.test(t)?!0:"Project name must be lowercase and contain only alphanumeric characters, hyphens, and underscores."},{type:"input",name:"description",message:"Project description:",initial:"A Next.js application"},{type:"input",name:"author",message:"Author:",initial:"Teispace"},{type:"input",name:"version",message:"Version:",initial:"0.1.0",validate:t=>/^\d+\.\d+\.\d+$/.test(t)?!0:"Version must be a valid semantic version (x.y.z)."},{type:"input",name:"email",message:"Support email:",initial:"support@example.com",validate:t=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)?!0:"Please enter a valid email address."},{type:"select",name:"packageManager",message:"Which package manager would you like to use?",choices:["npm","yarn","pnpm","bun"],initial:1},{type:"input",name:"gitRemote",message:"GitHub repository URL (optional):",initial:""},{type:"confirm",name:"pushToRemote",message:"Would you like to push the changes to the remote repository?",initial:!0,skip:function(){return!this.state?.answers?.gitRemote}},{type:"input",name:"gitIssues",message:"GitHub issues URL (optional):",initial:"",skip:function(){return!this.state?.answers?.gitRemote},validate:t=>t?/^https:\/\/github\.com\/[\w-]+\/[\w.-]+\/issues$/.test(t)?!0:"Please enter a valid GitHub issues URL (e.g., https://github.com/user/repo/issues)":!0},{type:"input",name:"gitHomepage",message:"GitHub homepage URL (optional):",initial:"",skip:function(){return!this.state?.answers?.gitRemote},validate:t=>t?/^https:\/\/github\.com\/[\w-]+\/[\w.-]+#readme$/.test(t)?!0:"Please enter a valid GitHub homepage URL (e.g., https://github.com/user/repo#readme)":!0},{type:"confirm",name:"keepTemplates",message:"Do you want to keep GitHub issue and pull request templates?",initial:!1},{type:"select",name:"httpClient",message:"Which HTTP client do you want to use?",choices:["axios","fetch","both","none"],initial:1},{type:"confirm",name:"reactSecureStorage",message:"Do you want to include react-secure-storage?",initial:!0,skip:function(){let t=this.state?.answers??this.enquirer?.answers??{};return!!(t.httpClient&&t.httpClient!=="none")}},{type:"confirm",name:"darkMode",message:"Do you want to include Dark Mode (Tailwind + @teispace/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:"confirm",name:"tests",message:"Do you want to include testing setup (Vitest + React Testing Library)?",initial:!0},{type:"confirm",name:"reactCompiler",message:"Do you want to enable the React Compiler?",initial:!0},{type:"confirm",name:"bundleAnalyzer",message:"Do you want to include @next/bundle-analyzer?",initial:!1},{type:"multiselect",name:"communityFiles",message:"Select community files to include:",choices:[{name:"CODE_OF_CONDUCT.md",value:"CODE_OF_CONDUCT.md"},{name:"CONTRIBUTING.md",value:"CONTRIBUTING.md"},{name:"SECURITY.md",value:"SECURITY.md"}],initial:[]},{type:"confirm",name:"readme",message:"Do you want to create a README.md?",initial:!0},{type:"confirm",name:"docker",message:"Do you want to include Docker configuration?",initial:!1},{type:"input",name:"containerName",message:"Docker Container Name:",initial:"next-app",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:t=>/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(t)?!0:"Invalid Docker container name."},{type:"input",name:"imageName",message:"Docker Image Name:",initial:"nextjs-starter",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:t=>/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(t)?!0:"Invalid Docker image name (must be lowercase)."},{type:"input",name:"imageTag",message:"Docker Image Tag:",initial:"latest",skip:function(){return!(this.state?.answers??this.enquirer?.answers??{}).docker},validate:t=>/^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$/.test(t)?!0:"Invalid Docker image tag."},{type:"confirm",name:"ci",message:"Do you want to include GitHub Actions (CI/CD)?",initial:!1},{type:"confirm",name:"preCommitHooks",message:"Do you want to setup pre-commit hooks (Husky, Commitlint, Lint-staged)?",initial:!0},{type:"confirm",name:"commitizen",message:"Do you want to setup Commitizen?",initial:!0},{type:"confirm",name:"copyEnv",message:"Want to copy .env.example to .env?",initial:!0}]);if(r.company=r.author,r.gitRemote&&!r.gitHomepage){let t=r.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");r.gitHomepage=`${t}#readme`,r.gitIssues=`${t}/issues`}return r};P();import Oi from"node:path";var ne=async(e,r)=>{let t=_i(r);await f(Oi.join(e,"test/test-utils.tsx"),t)},_i=({redux:e,i18n:r})=>e&&r?Fi:e?ji:r?Di:Li,Fi=`import { type RenderOptions, render } from '@testing-library/react';
|
|
11
|
+
`,await g(r,n))}},Mt=async(e,t,r)=>{if(t===r)return;let n=t==="fetch"?"fetchClient":"axiosClient",o=r==="fetch"?"fetchClient":"axiosClient",i=t==="fetch"?"fetch-client":"axios-client",s=r==="fetch"?"fetch-client":"axios-client",a=D.join(e,"src");try{let p=`grep -rl "${n}" "${a}" --include="*.ts" --include="*.tsx" || true`,{stdout:d}=await Ft(p);if(!d.trim())return;let u=d.trim().split(`
|
|
12
|
+
`).filter(h=>h);for(let h of u){if(!m(h))continue;let x=await f(h),k=!1,z=new RegExp(`(import\\s*\\{[^}]*?)\\b${n}\\b([^}]*?\\}\\s*from\\s*['"][^'"]*?/http['"])`,"g");z.test(x)&&(x=x.replace(z,`$1${o}$2`),k=!0);let $=new RegExp(`import\\s+${n}\\s+from\\s+['"]([^'"]*?)/${i}['"]`,"g");$.test(x)&&(x=x.replace($,`import ${o} from '$1/${s}'`),k=!0);let J=new RegExp(`\\b${n}\\b(?=\\.)`,"g");J.test(x)&&(x=x.replace(J,o),k=!0);let he=new RegExp(`\\b${n}\\b(?![.\\w])`,"g");he.test(x)&&(x=x.replace(he,o),k=!0),k&&await g(h,x)}}catch(p){console.warn("Warning: Could not scan for HTTP client usages:",p)}},Gt=async e=>{let t=D.join(e,c.UTILS_INDEX);if(m(t)){let n=await f(t);n=n.replace(/^\s*export\s+\*\s+from\s+['"]\.\/http['"];?.*$/gm,""),await g(t,n)}let r=D.join(e,c.TYPES_INDEX);if(m(r)){let n=await f(r),o=D.join(e,c.COMMON_TYPES_DIR);if(!m(o))n=n.replace(/^\s*export\s+\*\s+from\s+['"]\.\/common['"];?.*$/gm,"");else{let i=D.join(o,"index.ts");if(m(i)){let s=await f(i);s=s.replace(/^\s*export\s+\*\s+from\s+['"]\.\/http\.types['"];?.*$/gm,""),await g(i,s)}}m(D.join(e,c.UTILITY_TYPES_DIR))||(n=n.replace(/^\s*export\s+\*\s+from\s+['"]\.\/utility['"];?.*$/gm,"")),await g(r,n)}},Es=async(e,t,r=[])=>{let n=D.join(e,"src"),i=`grep -r "from ['\\"].*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}.*['\\"]" "${n}" --include="*.ts" --include="*.tsx" || true`;try{let{stdout:s}=await Ft(i);return s.trim()?s.trim().split(`
|
|
13
|
+
`).filter(d=>{let[u]=d.split(":"),h=D.resolve(e,u);return!r.some(x=>!!(h===x||h.startsWith(x+D.sep)))}).length>0:!1}catch(s){return console.warn(`Warning: Failed to check usage for ${t}:`,s),!0}},bs=async(e,t,r=[])=>{let n=D.join(e,"src"),i=`grep -r "${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}" "${n}" --include="*.ts" --include="*.tsx" || true`;try{let{stdout:s}=await Ft(i);return s.trim()?s.trim().split(`
|
|
14
|
+
`).filter(d=>{let[u]=d.split(":"),h=D.resolve(e,u);return!r.some(x=>!!(h===x||h.startsWith(x+D.sep)))}).length>0:!1}catch(s){return console.warn(`Warning: Failed to check usage for string ${t}:`,s),!0}}});import{existsSync as ea}from"node:fs";import{access as ta}from"node:fs/promises";import xn from"node:path";var le,ft,Pn=be(()=>{"use strict";le=async(e,t,r)=>{try{return await ta(xn.join(e,r,t)),!0}catch{return!1}},ft=(e,t,r)=>ea(xn.join(e,t,r))});import{access as Jt,readFile as ra}from"node:fs/promises";import gt from"node:path";var A,vn=be(()=>{"use strict";A=async e=>{try{let t=gt.join(e,"package.json"),r=await ra(t,"utf-8"),n=JSON.parse(r),o={...n.dependencies,...n.devDependencies},i=!!(o["@reduxjs/toolkit"]&&o["react-redux"]),s=!!o["next-intl"],a=!!o.axios,p=!1,d=gt.join(e,"src","lib","utils","http","axios-client");try{await Jt(d)}catch{a=!1}let u=gt.join(e,"src","lib","utils","http","fetch-client");try{await Jt(u),p=!0}catch{p=!1}let h;a&&p?h="both":a?h="axios":p?h="fetch":h="none";let x=!!o.vitest;if(!x)try{await Jt(gt.join(e,"vitest.config.ts")),x=!0}catch{}return{hasRedux:i,httpClient:h,hasI18n:s,hasTests:x}}catch(t){throw new Error(`Failed to detect project setup: ${t}`,{cause:t})}}});var De={};Nt(De,{detectProjectSetup:()=>A,directoryExists:()=>le,fileExistsAt:()=>ft});var G=be(()=>{"use strict";Pn();vn()});import{Command as Zp}from"commander";import Ut from"node:path";import X from"picocolors";function Lr(e){let{logger:t=s=>console.error(s),exitOnCancel:r=process.env.NODE_ENV!=="test"}=e??{},n=()=>{console.log(""),console.log(""),t("Setup cancelled by user"),console.log(""),r&&process.exit(0)},o=s=>{if(s!==null&&typeof s=="object"&&"code"in s&&s.code==="ERR_USE_AFTER_CLOSE"){n();return}if(s instanceof Error){t(`Uncaught exception: ${s.message}`);return}t(`Uncaught exception: ${String(s)}`)},i=s=>{if(s instanceof Error){t(`Unhandled promise rejection: ${s.message}`);return}t(`Unhandled promise rejection: ${String(s)}`)};return process.on("SIGINT",n),process.on("SIGTERM",n),process.on("uncaughtException",o),process.on("unhandledRejection",i),()=>{process.off("SIGINT",n),process.off("SIGTERM",n),process.off("uncaughtException",o),process.off("unhandledRejection",i)}}import Q from"picocolors";var Wi={reset:e=>e,red:Q.red,green:Q.green,yellow:Q.yellow,blue:Q.blue,cyan:Q.cyan,magenta:Q.magenta,white:Q.white,gray:Q.gray,bright:Q.bold,dim:Q.dim};function ae(e,t="reset"){let r=Wi[t]??(n=>n);console.log(r(e))}function lt(e){ae(`\u2716 ${e}`,"red")}var v=lt;function Mr(e){ae(`\u26A0 ${e}`,"yellow")}function l(e){ae(e)}function Gr(){console.log(""),ae("\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"),ae("\u2551 \u2551","cyan"),ae("\u2551 \u{1F680} Create Teispace Next.js App \u{1F680} \u2551","cyan"),ae("\u2551 \u2551","cyan"),ae("\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("")}import Yi from"ora";function b(e="",t){let r=Yi({text:e,...t});return r.start(),r}var Ki=e=>e.charAt(0).toUpperCase()+e.slice(1),O=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),R=e=>Ki(O(e));import Zi from"ora";var y=Zi();P();import{exec as Qi}from"node:child_process";import{promisify as es}from"node:util";var ne=es(Qi),Ur=async(e,t,r)=>{try{if(await ne("git init",{cwd:e}),await ne("git add .",{cwd:e}),await ne('git commit -m "Initial commit from @teispace/next-maker"',{cwd:e}),t&&(await ne(`git remote add origin ${t}`,{cwd:e}),r)){await ne("git fetch origin",{cwd:e});let n="main";try{await ne("git show-branch origin/main",{cwd:e})}catch{try{await ne("git show-branch origin/master",{cwd:e}),n="master"}catch{n="main"}}await ne(`git merge origin/${n} --allow-unrelated-histories -X ours`,{cwd:e}),await ne(`git push origin HEAD:${n}`,{cwd:e})}}catch(n){console.warn("Failed to initialize git repository",n)}};import{exec as ts}from"node:child_process";import{promisify as rs}from"node:util";var Fe=rs(ts),zr=async(e,t)=>{let r=`${t} install`;try{await Fe(r,{cwd:e})}catch(n){throw new Error(`Failed to install dependencies with ${t}: ${n}`,{cause:n})}},B=async(e,t,r)=>{let n=t==="npm"?`${t} run ${r}`:`${t} ${r}`;try{await Fe(n,{cwd:e})}catch(o){console.warn(`Warning: Failed to run script '${r}': ${o}`)}},ns=()=>{let e=process.env.npm_config_user_agent;if(e){if(e.startsWith("yarn"))return"yarn";if(e.startsWith("pnpm"))return"pnpm";if(e.startsWith("bun"))return"bun"}return"npm"},_=async e=>{let{existsSync:t}=await import("node:fs"),r=await import("node:path");return t(r.join(e,"pnpm-lock.yaml"))?"pnpm":t(r.join(e,"yarn.lock"))?"yarn":t(r.join(e,"bun.lockb"))?"bun":t(r.join(e,"package-lock.json"))?"npm":ns()},os=async(e,t,r)=>{if(r.length===0)return;let o=`${Jr(t)} ${r.join(" ")}`;try{await Fe(o,{cwd:e})}catch(i){throw new Error(`Failed to install packages with ${t}: ${i}`,{cause:i})}},Jr=e=>{switch(e){case"npm":return"npm install";case"yarn":return"yarn add";case"pnpm":return"pnpm add";case"bun":return"bun add";default:return"npm install"}},q=async(e,t)=>{let r=await _(e);await os(e,r,[t])},is=e=>{switch(e){case"npm":return"--save-dev";case"yarn":case"pnpm":case"bun":return"-D";default:return"--save-dev"}},xe=async(e,t,r)=>{if(r.length===0)return;let n=Jr(t),o=is(t),i=`${n} ${o} ${r.join(" ")}`;try{await Fe(i,{cwd:e})}catch(s){throw new Error(`Failed to install dev packages with ${t}: ${s}`,{cause:s})}},mt=async(e,t)=>{let r=await _(e);await xe(e,r,[t])},At=async(e,t,r)=>{if(r.length===0)return;let o=`${ss(t)} ${r.join(" ")}`;try{await Fe(o,{cwd:e})}catch(i){throw new Error(`Failed to uninstall packages with ${t}: ${i}`,{cause:i})}},ss=e=>{switch(e){case"npm":return"npm uninstall";case"yarn":return"yarn remove";case"pnpm":return"pnpm remove";case"bun":return"bun remove";default:return"npm uninstall"}},Ot=async(e,t)=>{let r=await _(e);await At(e,r,[t])};import as from"enquirer";var cs=/^[a-z0-9-_]+$/,ps=/^\d+\.\d+\.\d+$/,ls=e=>cs.test(e),ms=e=>ps.test(e),Vr=(e,t={})=>{let r=t.projectName??e??"my-app";if(!ls(r))throw new Error(`Invalid project name "${r}". Use lowercase letters, digits, hyphens, and underscores only.`);let n=t.version??"0.1.0";if(!ms(n))throw new Error(`Invalid version "${n}". Expected semver (e.g. 0.1.0).`);let o=t.author??"Teispace",i=t.company??o;return{projectName:r,description:t.description??"A Next.js application",author:o,version:n,packageManager:t.packageManager??"yarn",gitRemote:t.gitRemote??"",pushToRemote:t.pushToRemote??!1,gitIssues:t.gitIssues??"",gitHomepage:t.gitHomepage??"",httpClient:t.httpClient??"fetch",reactSecureStorage:t.reactSecureStorage??!0,email:t.email??"support@example.com",company:i,keepTemplates:t.keepTemplates??!1,darkMode:t.darkMode??!0,redux:t.redux??!0,i18n:t.i18n??!0,communityFiles:t.communityFiles??[],readme:t.readme??!0,docker:t.docker??!1,containerName:t.containerName,imageName:t.imageName,imageTag:t.imageTag,ci:t.ci??!1,preCommitHooks:t.preCommitHooks??!0,commitizen:t.commitizen??!0,copyEnv:t.copyEnv??!0,tests:t.tests??!0,reactCompiler:t.reactCompiler??!0,bundleAnalyzer:t.bundleAnalyzer??!1}},{prompt:ds}=as,Br=async e=>{let t=await ds([{type:"input",name:"projectName",message:"What is the project name?",initial:e||"my-app",skip:!!e,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):",initial:""},{type:"confirm",name:"pushToRemote",message:"Would you like to push the changes to the remote repository?",initial:!0,skip:function(){return!this.state?.answers?.gitRemote}},{type:"input",name:"gitIssues",message:"GitHub issues URL (optional):",initial:"",skip:function(){return!this.state?.answers?.gitRemote},validate:r=>r?/^https:\/\/github\.com\/[\w-]+\/[\w.-]+\/issues$/.test(r)?!0:"Please enter a valid GitHub issues URL (e.g., https://github.com/user/repo/issues)":!0},{type:"input",name:"gitHomepage",message:"GitHub homepage URL (optional):",initial:"",skip:function(){return!this.state?.answers?.gitRemote},validate:r=>r?/^https:\/\/github\.com\/[\w-]+\/[\w.-]+#readme$/.test(r)?!0:"Please enter a valid GitHub homepage URL (e.g., https://github.com/user/repo#readme)":!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 + @teispace/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:"confirm",name:"tests",message:"Do you want to include testing setup (Vitest + React Testing Library)?",initial:!0},{type:"confirm",name:"reactCompiler",message:"Do you want to enable the React Compiler?",initial:!0},{type:"confirm",name:"bundleAnalyzer",message:"Do you want to include @next/bundle-analyzer?",initial:!1},{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(t.company=t.author,t.gitRemote&&!t.gitHomepage){let r=t.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"");t.gitHomepage=`${r}#readme`,t.gitIssues=`${r}/issues`}return t};P();import us from"node:path";var ce=async(e,t)=>{let r=fs(t);await g(us.join(e,"test/test-utils.tsx"),r)},fs=({redux:e,i18n:t})=>e&&t?gs:e?hs:t?ys:xs,gs=`import { type RenderOptions, render } from '@testing-library/react';
|
|
15
15
|
import { NextIntlClientProvider } from 'next-intl';
|
|
16
16
|
import type { ReactElement, ReactNode } from 'react';
|
|
17
17
|
import { Provider } from 'react-redux';
|
|
@@ -72,7 +72,7 @@ export function renderWithProviders(
|
|
|
72
72
|
|
|
73
73
|
export * from '@testing-library/react';
|
|
74
74
|
export { default as userEvent } from '@testing-library/user-event';
|
|
75
|
-
`,
|
|
75
|
+
`,hs=`import { type RenderOptions, render } from '@testing-library/react';
|
|
76
76
|
import type { ReactElement, ReactNode } from 'react';
|
|
77
77
|
import { Provider } from 'react-redux';
|
|
78
78
|
import { type AppState, type AppStore, makeStore } from '@/store';
|
|
@@ -111,7 +111,7 @@ export function renderWithProviders(
|
|
|
111
111
|
|
|
112
112
|
export * from '@testing-library/react';
|
|
113
113
|
export { default as userEvent } from '@testing-library/user-event';
|
|
114
|
-
`,
|
|
114
|
+
`,ys=`import { type RenderOptions, render } from '@testing-library/react';
|
|
115
115
|
import { NextIntlClientProvider } from 'next-intl';
|
|
116
116
|
import type { ReactElement, ReactNode } from 'react';
|
|
117
117
|
import type { SupportedLocale } from '@/types/i18n';
|
|
@@ -151,7 +151,7 @@ export function renderWithProviders(
|
|
|
151
151
|
|
|
152
152
|
export * from '@testing-library/react';
|
|
153
153
|
export { default as userEvent } from '@testing-library/user-event';
|
|
154
|
-
`,
|
|
154
|
+
`,xs=`import { type RenderOptions, render } from '@testing-library/react';
|
|
155
155
|
import type { ReactElement, ReactNode } from 'react';
|
|
156
156
|
|
|
157
157
|
type TestProvidersProps = {
|
|
@@ -173,32 +173,32 @@ export function renderWithProviders(ui: ReactElement, options: ExtendedRenderOpt
|
|
|
173
173
|
|
|
174
174
|
export * from '@testing-library/react';
|
|
175
175
|
export { default as userEvent } from '@testing-library/user-event';
|
|
176
|
-
`;import
|
|
177
|
-
`),await T(
|
|
178
|
-
`};o("CONTAINER_NAME",
|
|
176
|
+
`;import Xr from"node:path";var C={REDUX_TOOLKIT:"@reduxjs/toolkit",REACT_REDUX:"react-redux",REDUX:"redux",REDUX_PERSIST:"redux-persist",REACT_SECURE_STORAGE:"react-secure-storage",NEXT_INTL:"next-intl",NEXT_THEMES:"@teispace/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",VITEST:"vitest",JSDOM:"jsdom",VITE_PLUGIN_REACT:"@vitejs/plugin-react",TESTING_LIBRARY_DOM:"@testing-library/dom",TESTING_LIBRARY_JEST_DOM:"@testing-library/jest-dom",TESTING_LIBRARY_REACT:"@testing-library/react",TESTING_LIBRARY_USER_EVENT:"@testing-library/user-event",REACT_COMPILER_BABEL:"babel-plugin-react-compiler",NEXT_BUNDLE_ANALYZER:"@next/bundle-analyzer"};S();P();var Wr=async(e,t)=>{if(t.bundleAnalyzer)return;let r=Xr.join(e,c.NEXT_CONFIG);if(m(r)){let n=await f(r);n=n.replace(/import\s+withBundleAnalyzer\s+from\s+'@next\/bundle-analyzer';\n/,""),n=n.replace(/const\s+bundleAnalyzer\s*=\s*withBundleAnalyzer\(\{[\s\S]*?\}\);\n+/,""),n=n.replace(/bundleAnalyzer\(([^)]*)\)/,"$1"),await g(r,n)}await F(Xr.join(e,c.PACKAGE_JSON),n=>(n.devDependencies&&delete n.devDependencies[C.NEXT_BUNDLE_ANALYZER],n.scripts&&delete n.scripts.analyze,n))};S();P();import _e from"node:path";var Yr=async(e,t)=>{t.darkMode||(await T(_e.join(e,c.THEME_PROVIDER)),await Ps(e),await vs(e),await Ss(e))},Ps=async e=>{let t=_e.join(e,c.PROVIDERS_INDEX),r=await f(t);r=r.replace(/export \* from '\.\/CustomThemeProvider';\n/,""),await g(t,r)},vs=async e=>{let t=_e.join(e,c.GLOBALS_CSS);if(m(t)){let r=await f(t);r=r.replace(/@custom-variant dark \(.*?\);\n\n/,""),r=r.replace(/@theme \{[\s\S]*?\}\n/,""),await g(t,r)}},ws=e=>e.replace(/\bbg-light\b\s?/g,"").replace(/\bdark:bg-dark\b\s?/g,"").replace(/\s{2,}/g," ").replace(/suppressHydrationWarning=\{true\}/g,""),Ss=async e=>{let t=[_e.join(e,c.ROOT_LAYOUT),_e.join(e,"src/app/[locale]/layout.tsx")];for(let r of t)if(m(r)){let n=await f(r),o=ws(n);o!==n&&await g(r,o)}};S();P();dt();import I from"node:path";var Zr=async(e,t)=>{let r=I.join(e,c.HTTP_UTILS),n=t.httpClient!=="none"||!!t.reactSecureStorage;t.httpClient==="none"?await Rs(e,r,n):t.httpClient==="axios"?await $s(e,r):t.httpClient==="fetch"&&await Is(e,r)},Rs=async(e,t,r)=>{await w(I.join(e,c.AXIOS_CLIENT)),await w(I.join(e,c.FETCH_CLIENT)),r?(await g(I.join(t,"index.ts"),`export * from './token-store';
|
|
177
|
+
`),await T(I.join(e,c.CLIENT_UTILS)),await Re(e,[])):(await w(t),await Ns(e),await T(I.join(e,c.APP_APIS)),await ks(e)),await As(e),await w(I.join(e,c.ERRORS_DIR)),r||(await w(I.join(e,c.COMMON_TYPES_DIR)),await w(I.join(e,c.UTILITY_TYPES_DIR)),await Os(e))},$s=async(e,t)=>{await w(I.join(e,c.FETCH_CLIENT));let r=await f(I.join(t,"index.ts"));r=r.replace(/export .* from '\.\/fetch-client';\n/g,""),await g(I.join(t,"index.ts"),r);let n=I.join(e,c.HTTP_TYPES);if(m(n)){let o=await f(n);o=o.replace(/export interface FetchClientOptions \{[\s\S]*?\}\n\n/,""),o=o.replace(/export interface ExtendedRequestInit extends RequestInit \{[\s\S]*?\}\n\n/,""),await g(n,o)}},Is=async(e,t)=>{await w(I.join(e,c.AXIOS_CLIENT));let r=await f(I.join(t,"index.ts"));r=r.replace(/export .* from '\.\/axios-client';\n/g,""),await g(I.join(t,"index.ts"),r),await Re(e,["fetch"]);let n=I.join(e,c.HTTP_TYPES);if(m(n)){let o=await f(n);o=o.replace(/export interface AxiosClientOptions \{[\s\S]*?\}\n\n/,""),await g(n,o)}},Ns=async e=>{let t=I.join(e,c.UTILS_INDEX);if(m(t)){let r=await f(t);r=r.replace(/export \* from '\.\/http';\n/,""),await g(t,r)}},ks=async e=>{let t=I.join(e,c.CONFIG_INDEX);if(m(t)){let r=await f(t);r=r.replace(/export \* from '\.\/app-apis';\n/,""),await g(t,r)}},As=async e=>{let t=I.join(e,c.CONSTANTS);if(m(t)){let r=await f(t);r=r.replace(/export const API_RESPONSE_DATA_KEY = 'data';\n/,""),r=r.replace(/export const SAVE_AUTH_TOKENS = false;\n/,""),await g(t,r)}},Os=async e=>{let t=I.join(e,c.TYPES_INDEX);if(m(t)){let r=await f(t);r=r.replace(/export \* from '\.\/utility';\n/,""),r=r.replace(/export \* from '\.\/common';\n/,""),await g(t,r)}};S();P();import V from"node:path";var Qr=async(e,t)=>{t.i18n||(await _s(e),await js(e),await Ds(e),await Ls(e),await Fs(e))},Fs=async e=>{let t=V.join(e,c.ENV_EXAMPLE);if(!m(t))return;let r=await f(t);r=r.replace(/#[^\n]*IANA time zone[\s\S]*?DEFAULT_TIMEZONE=[^\n]*\n?/,""),r=r.replace(/#[^\n]*Fallback locale[\s\S]*?DEFAULT_LOCALE=[^\n]*\n?/,""),r=r.replace(/^DEFAULT_TIMEZONE=.*\n?/m,""),r=r.replace(/^DEFAULT_LOCALE=.*\n?/m,""),await g(t,r)},_s=async e=>{await w(V.join(e,c.I18N_DIR)),await w(V.join(e,c.LOCALE_DIR)),await T(V.join(e,c.PROXY)),await T(V.join(e,c.MIDDLEWARE)),await T(V.join(e,c.I18N_TYPES)),await T(V.join(e,c.APP_LOCALES))},js=async e=>{let t=V.join(e,c.TYPES_INDEX);if(m(t)){let n=await f(t);n=n.replace(/export \* from '\.\/i18n';\n/,""),await g(t,n)}let r=V.join(e,c.CONFIG_INDEX);if(m(r)){let n=await f(r);n=n.replace(/export \* from '\.\/app-locales';\n/,""),await g(r,n)}},Ds=async e=>{let t=V.join(e,c.NEXT_CONFIG);if(m(t)){let r=await f(t);r=r.replace(/import createNextIntlPlugin from 'next-intl\/plugin';\n/,""),r=r.replace(/const withNextIntl = createNextIntlPlugin\(\);\n+/,""),r=r.replace(/withNextIntl\(([^)]+)\)/,"$1"),await g(t,r)}},Ls=async e=>{let t=V.join(e,c.COUNTER_COMPONENT);if(m(t)){let o=await f(t);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,"Current Count: {value}"),o=o.replace(/\{t\(['"]increment['"]\)\}/g,"Increment"),o=o.replace(/\{t\(['"]decrement['"]\)\}/g,"Decrement"),o=o.replace(/\{t\(['"]reset['"]\)\}/g,"Reset"),await g(t,o)}let r=V.join(e,"src/features/counter/components/Counter.test.tsx"),n=V.join(e,"test/test-utils.tsx");await T(r),await T(n)};S();P();import pe from"node:path";var en=async(e,t)=>{t.httpClient!=="none"||t.reactSecureStorage||await w(pe.join(e,c.STORAGE_SERVICE))},tn=async e=>{await T(pe.join(e,c.LICENSE))},rn=async e=>{await T(pe.join(e,c.CHANGELOG))},nn=async e=>{await T(pe.join(e,c.NVM_RC)),await T(pe.join(e,c.NPM_RC))},on=async e=>{await w(pe.join(e,c.CLAUDE_DIR)),await w(pe.join(e,c.DOCS_DIR)),await w(pe.join(e,c.VSCODE_DIR))};import sn from"node:path";S();P();var an=async(e,t)=>{if(t.reactCompiler)return;let r=sn.join(e,c.NEXT_CONFIG);if(m(r)){let n=await f(r);n=n.replace(/^\s*reactCompiler:\s*true,?\n/m,""),await g(r,n)}await F(sn.join(e,c.PACKAGE_JSON),n=>(n.devDependencies&&delete n.devDependencies[C.REACT_COMPILER_BABEL],n))};S();P();import Pe from"node:path";var cn=async(e,t)=>{t.redux||(await w(Pe.join(e,c.STORE)),await w(Pe.join(e,c.COUNTER_FEATURE)),await T(Pe.join(e,c.STORE_PROVIDER)),await T(Pe.join(e,"test/test-utils.tsx")),await Ms(e),await Gs(e))},Ms=async e=>{let t=Pe.join(e,c.PROVIDERS_INDEX),r=await f(t);r=r.replace(/export \* from '\.\/StoreProvider';\n/,""),await g(t,r)},Gs=async e=>{let t=[Pe.join(e,c.ROOT_PAGE),Pe.join(e,c.LOCALE_PAGE)];for(let r of t)if(m(r)){let n=await f(r);n=n.replace(/import\s+\{\s*Counter\s*\}\s+from\s+['"]@\/features\/counter['"];\n?/,""),n=n.replace(/<Counter\s*\/>\n?/g,""),await g(r,n)}};import ut from"node:path";S();P();var Hs=[C.VITEST,C.JSDOM,C.VITE_PLUGIN_REACT,C.TESTING_LIBRARY_DOM,C.TESTING_LIBRARY_JEST_DOM,C.TESTING_LIBRARY_REACT,C.TESTING_LIBRARY_USER_EVENT],pn=async(e,t)=>{t.tests||(await T(ut.join(e,c.VITEST_CONFIG)),await w(ut.join(e,c.TEST_DIR)),await T(ut.join(e,"src/features/counter/components/Counter.test.tsx")),await F(ut.join(e,c.PACKAGE_JSON),r=>{if(r.devDependencies)for(let n of Hs)delete r.devDependencies[n];return r.scripts&&(delete r.scripts.test,delete r.scripts["test:watch"],delete r.scripts["test:coverage"],typeof r.scripts.validate=="string"&&(r.scripts.validate=r.scripts.validate.replace(/\s*&&\s*yarn\s+test(?![:\w])/,"").replace(/\byarn\s+test(?![:\w])\s*&&\s*/,""))),r}))};var ln=async(e,t)=>{let r=b("Customizing features...");try{await Zr(e,t),await en(e,t),await cn(e,t),await Yr(e,t),await Wr(e,t),await Qr(e,t),await an(e,t),await pn(e,t),await tn(e),await rn(e),await nn(e),await on(e),t.tests&&await ce(e,{redux:t.redux,i18n:t.i18n}),r.succeed("Features customized.")}catch(n){throw r.fail("Failed to customize features."),n}};import Us from"node:path";S();P();var mn=async(e,t)=>{let r=b("Configuring package.json...");try{let n=t.gitRemote,o=t.gitHomepage,i=t.gitIssues;t.gitRemote&&(t.gitRemote.startsWith("git@github.com:")&&(n=t.gitRemote.replace("git@github.com:","https://github.com/").replace(/\.git$/,"")),o||(o=`${n.replace(/\.git$/,"")}#readme`),i||(i=`${n.replace(/\.git$/,"")}/issues`),n.endsWith(".git")||(n=`${n}.git`)),await F(Us.join(e,c.PACKAGE_JSON),s=>(s.name=t.projectName,s.version=t.version,s.description=t.description,s.author=t.author,delete s.packageManager,t.gitRemote?(o&&(s.homepage=o),i&&(s.bugs={url:i}),n&&(s.repository={type:"git",url:n})):(delete s.homepage,delete s.bugs,delete s.repository),t.redux||(delete s.dependencies[C.REDUX_TOOLKIT],delete s.dependencies[C.REACT_REDUX],delete s.dependencies[C.REDUX],delete s.dependencies[C.REDUX_PERSIST]),t.httpClient!=="none"||t.reactSecureStorage||delete s.dependencies[C.REACT_SECURE_STORAGE],t.i18n||delete s.dependencies[C.NEXT_INTL],t.darkMode||delete s.dependencies[C.NEXT_THEMES],t.httpClient==="none"?delete s.dependencies[C.AXIOS]:t.httpClient==="fetch"&&delete s.dependencies[C.AXIOS],s)),r.succeed("package.json configured.")}catch(n){throw r.fail("Failed to configure package.json."),n}};import{readdir as dn}from"node:fs/promises";import N from"node:path";S();P();var un=async(e,t)=>{await zs(e,t),await Js(e,t),await Vs(e,t),await Bs(e,t),await qs(e,t),await Xs(e,t),await Ws(e,t)},zs=async(e,t)=>{t.preCommitHooks||(await w(N.join(e,c.HUSKY_DIR)),await T(N.join(e,c.COMMITLINT_CONFIG)),await T(N.join(e,c.LINTSTAGED_RC)),await F(N.join(e,c.PACKAGE_JSON),r=>(delete r.devDependencies[C.HUSKY],delete r.devDependencies[C.COMMITLINT_CLI],delete r.devDependencies[C.COMMITLINT_CONFIG],delete r.devDependencies[C.LINT_STAGED],delete r.scripts.prepare,delete r.scripts.postinstall,delete r.commitlint,delete r["lint-staged"],r)))},Js=async(e,t)=>{t.commitizen||(await T(N.join(e,c.CZRC)),await F(N.join(e,c.PACKAGE_JSON),r=>(delete r.devDependencies[C.COMMITIZEN],delete r.devDependencies[C.CZ_CONVENTIONAL_CHANGELOG],delete r.config?.commitizen,r.config&&Object.keys(r.config).length===0&&delete r.config,delete r.scripts.commit,r)))},Vs=async(e,t)=>{t.ci||await w(N.join(e,c.GITHUB_WORKFLOWS))},Bs=async(e,t)=>{let r=N.join(e,c.GITHUB_DIR);if(!t.keepTemplates)await w(N.join(r,c.GITHUB_ISSUE_TEMPLATE)),await T(N.join(r,c.GITHUB_PR_TEMPLATE));else{let n=N.join(r,c.GITHUB_ISSUE_TEMPLATE),o=N.join(r,c.GITHUB_PR_TEMPLATE),i=s=>s.replace(/Teispace/g,t.company).replace(/support@teispace\.com/g,t.email).replace(/Next\.js Starter/g,t.projectName).replace(/\[AUTHOR\]/g,t.author).replace(/\[COMPANY\]/g,t.company).replace(/\[EMAIL\]/g,t.email);if(m(o)){let s=await f(o);s=i(s),await g(o,s)}try{if(m(n)){let s=await dn(n);for(let a of s){let p=N.join(n,a),d=await f(p);d=i(d),await g(p,d)}}}catch{}}},qs=async(e,t)=>{let r=[c.CODE_OF_CONDUCT,c.CONTRIBUTING,c.SECURITY];for(let n of r)t.communityFiles.includes(n)||await T(N.join(e,n))},Xs=async(e,t)=>{if(t.docker){let r=N.join(e,c.ENV_EXAMPLE);if(m(r)){let n=await f(r),o=(i,s)=>{let a=new RegExp(`${i}=.*`);a.test(n)?n=n.replace(a,`${i}=${s}`):n+=`${i}=${s}
|
|
178
|
+
`};o("CONTAINER_NAME",t.containerName||"next-app"),o("IMAGE_NAME",t.imageName||"nextjs-starter"),o("IMAGE_TAG",t.imageTag||"latest"),await g(r,n)}}else{await T(N.join(e,c.DOCKERFILE)),await T(N.join(e,c.DOCKER_COMPOSE)),await T(N.join(e,c.DOCKERIGNORE));let r=N.join(e,c.ENV_EXAMPLE);if(m(r)){let n=await f(r);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 g(r,n)}}},Ws=async(e,t)=>{let r=async i=>{let s=await dn(i,{withFileTypes:!0}),a=[];for(let p of s){let d=N.join(i,p.name);p.isDirectory()&&p.name!=="node_modules"&&p.name!==".git"?a.push(...await r(d)):p.isFile()&&p.name.toLowerCase()==="readme.md"&&a.push(d)}return a},n=await r(e),o=N.join(e,c.README);for(let i of n)i!==o&&await T(i);if(t.readme){let i=`# ${t.projectName}
|
|
179
179
|
|
|
180
|
-
${
|
|
180
|
+
${t.description}
|
|
181
181
|
|
|
182
182
|
## Getting Started
|
|
183
183
|
|
|
184
184
|
First, run the development server:
|
|
185
185
|
|
|
186
186
|
\`\`\`bash
|
|
187
|
-
${
|
|
187
|
+
${t.packageManager==="npm"?"npm run dev":`${t.packageManager} dev`}
|
|
188
188
|
\`\`\`
|
|
189
189
|
|
|
190
190
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
191
|
-
`;await
|
|
191
|
+
`;await g(o,i)}else await T(o)};S();P();import Ht from"node:path";var fn=async(e,t)=>{let r=[];t.i18n&&r.push("import { type AbstractIntlMessages, NextIntlClientProvider } from 'next-intl';"),t.darkMode&&r.push("import { CustomThemeProvider } from '@/providers';"),t.redux&&r.push("import type { AppState } from '@/store';"),t.i18n&&r.push("import type { SupportedLocale } from '@/types/i18n';"),t.redux&&r.push("import { StoreProvider } from './StoreProvider';");let n=["children: React.ReactNode;"],o=["children"];t.i18n&&(n.push("locale: SupportedLocale;"),n.push("messages: AbstractIntlMessages;"),n.push("timeZone: string;"),o.push("locale","messages","timeZone")),t.redux&&(n.push("preloadedState?: Partial<AppState>;"),o.push("preloadedState"));let i="{children}";t.i18n&&(i=`<NextIntlClientProvider locale={locale} messages={messages} timeZone={timeZone}>
|
|
192
192
|
${i}
|
|
193
|
-
</NextIntlClientProvider>`),
|
|
193
|
+
</NextIntlClientProvider>`),t.darkMode&&(i=`<CustomThemeProvider>
|
|
194
194
|
${i}
|
|
195
|
-
</CustomThemeProvider>`),
|
|
195
|
+
</CustomThemeProvider>`),t.redux&&(i=`<StoreProvider preloadedState={preloadedState}>
|
|
196
196
|
${i}
|
|
197
197
|
</StoreProvider>`),i==="{children}"&&(i="<>{children}</>");let s=`type RootProviderProps = {
|
|
198
198
|
${n.join(`
|
|
199
199
|
`)}
|
|
200
200
|
};`,a=`'use client';
|
|
201
|
-
${
|
|
201
|
+
${r.join(`
|
|
202
202
|
`)}
|
|
203
203
|
|
|
204
204
|
${s}
|
|
@@ -208,7 +208,7 @@ export const RootProvider = ({ ${o.join(", ")} }: RootProviderProps) => {
|
|
|
208
208
|
${i}
|
|
209
209
|
);
|
|
210
210
|
};
|
|
211
|
-
`;await
|
|
211
|
+
`;await g(Ht.join(e,c.ROOT_PROVIDER),a)},gn=async(e,t)=>{if(t.i18n)return;let r=`\`\${livvic.variable} ${t.darkMode?"bg-light antialiased dark:bg-dark":"antialiased"}\``,n=(t.redux,""),o=`import type { Metadata } from 'next';
|
|
212
212
|
import '@/styles/globals.css';
|
|
213
213
|
import { Livvic } from 'next/font/google';
|
|
214
214
|
import { RootProvider } from '@/providers';
|
|
@@ -221,8 +221,8 @@ const livvic = Livvic({
|
|
|
221
221
|
});
|
|
222
222
|
|
|
223
223
|
export const metadata: Metadata = {
|
|
224
|
-
title: '${
|
|
225
|
-
description: '${
|
|
224
|
+
title: '${t.projectName}',
|
|
225
|
+
description: '${t.description}',
|
|
226
226
|
};
|
|
227
227
|
|
|
228
228
|
export default function RootLayout({
|
|
@@ -231,8 +231,8 @@ export default function RootLayout({
|
|
|
231
231
|
children: React.ReactNode;
|
|
232
232
|
}>) {
|
|
233
233
|
return (
|
|
234
|
-
<html lang="en"${
|
|
235
|
-
<body className={${
|
|
234
|
+
<html lang="en"${t.darkMode?" suppressHydrationWarning={true}":""}>
|
|
235
|
+
<body className={${r}}>
|
|
236
236
|
<RootProvider${n}>
|
|
237
237
|
{children}
|
|
238
238
|
</RootProvider>
|
|
@@ -240,31 +240,31 @@ export default function RootLayout({
|
|
|
240
240
|
</html>
|
|
241
241
|
);
|
|
242
242
|
}
|
|
243
|
-
`;await
|
|
243
|
+
`;await g(Ht.join(e,c.ROOT_LAYOUT),o);let i=t.redux?`import { Counter } from '@/features/counter';
|
|
244
244
|
|
|
245
|
-
`:"",s=
|
|
245
|
+
`:"",s=t.redux?`
|
|
246
246
|
<Counter />`:"",a=`${i}export default function Home() {
|
|
247
247
|
return (
|
|
248
248
|
<div className="flex min-h-screen flex-col items-center justify-center p-24">
|
|
249
|
-
<h1 className="text-4xl font-bold">Welcome to ${
|
|
249
|
+
<h1 className="text-4xl font-bold">Welcome to ${t.projectName}</h1>
|
|
250
250
|
<p className="mt-4 text-xl">Get started by editing src/app/page.tsx</p>${s}
|
|
251
251
|
</div>
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
|
-
`;await
|
|
255
|
-
Cleaning up: Deleting directory ${
|
|
256
|
-
Process interrupted. Cleaning up...`)),await i(),process.exit(1)};process.on("SIGINT",s),process.on("SIGTERM",s);try{if(await
|
|
257
|
-
`)},
|
|
258
|
-
`;var
|
|
259
|
-
`);let a=
|
|
260
|
-
`;
|
|
254
|
+
`;await g(Ht.join(e,c.ROOT_PAGE),a)};import Ys from"degit";var hn=async e=>{let t=b("Downloading template...");try{await Ys("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!0}).clone(e),t.succeed("Template downloaded successfully.")}catch(r){throw t.fail("Failed to download template."),r}};var zt=["npm","yarn","pnpm","bun"],Ks=e=>{if(e!==void 0){if(!zt.includes(e))throw new Error(`Invalid --package-manager "${e}". Valid: ${zt.join(", ")}.`);return e}},yn=e=>{e.command("init").description("Initialize a new Next.js project").argument("[name]","Project name").option("-y, --yes","Skip all prompts and use the recommended production defaults").option("--package-manager <pm>",`Override the package manager (one of: ${zt.join(", ")})`).action(async(t,r)=>{try{let n=Ks(r.packageManager);await Qs(t,{yes:r.yes??!1,packageManager:n})}catch(n){v(`${n instanceof Error?n.message:n}`),process.exit(1)}})},je=async(e,t,r,n)=>{let o=b(e);n.current=o;try{let i=await r();return o.succeed(t),i}finally{n.current===o&&(n.current=null)}},Zs=e=>{let t=[];e.darkMode&&t.push("dark mode"),e.redux&&t.push("redux"),e.i18n&&t.push("i18n"),e.tests&&t.push("tests"),e.reactCompiler&&t.push("react-compiler"),e.preCommitHooks&&t.push("pre-commit hooks"),e.commitizen&&t.push("commitizen"),e.httpClient!=="none"&&t.push(`http (${e.httpClient})`),l(X.dim("Defaults applied (run `next-maker remove <feature>` to undo any of them):")),l(X.dim(` package manager : ${e.packageManager}`)),l(X.dim(` features : ${t.join(", ")}`)),l("")},Qs=async(e,t)=>{Gr();let r;t.yes?(r=Vr(e,{packageManager:t.packageManager}),l(X.cyan(`\u2728 Bootstrapping ${r.projectName} with the recommended defaults`)),l(""),Zs(r)):(l("Welcome to the Teispace Next.js App Creator!"),l(""),r=await Br(e),t.packageManager&&(r={...r,packageManager:t.packageManager}));let n=Ut.resolve(process.cwd(),r.projectName);m(n)&&(console.error(X.red(`Error: Directory ${r.projectName} already exists.`)),process.exit(1));let o={current:null},i=async()=>{if(m(n)){o.current?.stop(),o.current=null,console.log(X.yellow(`
|
|
255
|
+
Cleaning up: Deleting directory ${r.projectName}...`));try{await w(n),console.log(X.green("Cleanup successful."))}catch(a){console.error(X.red(`Failed to clean up directory ${r.projectName}:`),a)}}},s=async()=>{console.log(X.red(`
|
|
256
|
+
Process interrupted. Cleaning up...`)),await i(),process.exit(1)};process.on("SIGINT",s),process.on("SIGTERM",s);try{if(await hn(n),await mn(n,r),await ln(n,r),await je("Generating providers and layout...","Providers and layout generated.",async()=>{await fn(n,r),await gn(n,r)},o),await je("Setting up developer tools...","Developer tools configured.",()=>un(n,r),o),await je("Initializing Git...","Git initialized.",()=>Ur(n,r.gitRemote,r.pushToRemote),o),await je("Installing dependencies...","Dependencies installed.",()=>zr(n,r.packageManager),o),await je("Formatting and linting...","Formatted.",()=>B(n,r.packageManager,"lint:fix"),o),r.copyEnv){let a=Ut.join(n,".env.example"),p=Ut.join(n,".env");m(a)&&await(await import("node:fs/promises")).copyFile(a,p)}process.off("SIGINT",s),process.off("SIGTERM",s),l(""),l(X.green(`\u2728 Project ${r.projectName} created successfully!`)),l(""),l("To get started:"),l(X.cyan(` cd ${r.projectName}`)),l(X.cyan(` ${r.packageManager==="npm"?"npm run dev":`${r.packageManager} dev`}`)),l("")}catch(a){o.current?.fail("Failed to create project."),o.current=null,console.error(a),await i(),process.exit(1)}};import or from"node:path";import ee from"picocolors";G();import{mkdir as Sn,writeFile as Bt}from"node:fs/promises";import ve from"node:path";P();var Vt=e=>{let{componentName:t,isClient:r,hasI18n:n}=e,o=e.translationNamespace||t,i=[];return(r||n)&&i.push("'use client';"),n&&i.push("import { useTranslations } from 'next-intl';"),i.push(""),i.push(`export function ${t}() {`),n?(i.push(` const t = useTranslations('${o}');`),i.push(""),i.push(" return ("),i.push(" <div>"),i.push(" <h2>{t('title')}</h2>"),i.push(" </div>"),i.push(" );")):(i.push(" return ("),i.push(" <div>"),i.push(` <h2>${t}</h2>`),i.push(" </div>"),i.push(" );")),i.push("}"),i.push(""),i.join(`
|
|
257
|
+
`)},wn=e=>`export { ${e.componentName} } from './${e.componentName}';
|
|
258
|
+
`;var qt=async e=>{let{name:t,projectPath:r,isClient:n,hasI18n:o,featurePath:i}=e,s=R(t);i?await na(s,r,i,n,o):await oa(s,t,r,n,o)},na=async(e,t,r,n,o)=>{let i=ve.join(t,r,"components");await Sn(i,{recursive:!0}),await Bt(ve.join(i,`${e}.tsx`),Vt({componentName:e,isClient:n,hasI18n:o}))},oa=async(e,t,r,n,o)=>{let i=ve.join(r,"src","components","common",e);await Sn(i,{recursive:!0}),await Bt(ve.join(i,`${e}.tsx`),Vt({componentName:e,isClient:n,hasI18n:o})),await Bt(ve.join(i,"index.ts"),wn({componentName:e}));let s=ve.join(r,"src","components","common","index.ts");await ia(s,`export { ${e} } from './${e}';
|
|
259
|
+
`);let a=ve.join(r,"src","components","index.ts");await sa(a)},ia=async(e,t)=>{let r="";m(e)&&(r=await f(e)),r.includes(t.trim())||(r+=t,await g(e,r))},sa=async e=>{let t="";m(e)&&(t=await f(e));let r=`export * from './common';
|
|
260
|
+
`;t.includes(r.trim())||(t+=r,await g(e,t))};import{writeFile as aa}from"node:fs/promises";import ca from"node:path";var Cn=e=>{let{camelName:t,pascalName:r,httpClient:n}=e,o=n==="axios"?"import { axiosClient } from '@/lib/utils/http';":"import { fetchClient } from '@/lib/utils/http';",i=n==="axios"?"axiosClient":"fetchClient";return`import { AppApis } from '@/lib/config';
|
|
261
261
|
${o}
|
|
262
262
|
import type { ResultAsync } from '@/types';
|
|
263
263
|
|
|
264
264
|
/**
|
|
265
265
|
* Summary type used in list responses (e.g., cards, tables).
|
|
266
266
|
*/
|
|
267
|
-
export interface ${
|
|
267
|
+
export interface ${r}Summary {
|
|
268
268
|
id: string;
|
|
269
269
|
// Add list/card fields here (title, thumbnail, status, etc.)
|
|
270
270
|
}
|
|
@@ -272,99 +272,99 @@ export interface ${t}Summary {
|
|
|
272
272
|
/**
|
|
273
273
|
* Detail type used in single-item responses (e.g., detail page).
|
|
274
274
|
*/
|
|
275
|
-
export interface ${
|
|
275
|
+
export interface ${r}Detail extends ${r}Summary {
|
|
276
276
|
// Add detailed fields here (content, metadata, relations, etc.)
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
export interface Create${
|
|
279
|
+
export interface Create${r}Dto {
|
|
280
280
|
// Add create fields here
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
export interface Update${
|
|
283
|
+
export interface Update${r}Dto {
|
|
284
284
|
// Add update fields here
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
export const ${
|
|
288
|
-
getAll: (): ResultAsync<${
|
|
289
|
-
return ${i}.get<${
|
|
287
|
+
export const ${t}Service = {
|
|
288
|
+
getAll: (): ResultAsync<${r}Summary[]> => {
|
|
289
|
+
return ${i}.get<${r}Summary[]>(AppApis.${t}.getAll);
|
|
290
290
|
},
|
|
291
291
|
|
|
292
|
-
getById: (id: string): ResultAsync<${
|
|
293
|
-
return ${i}.get<${
|
|
292
|
+
getById: (id: string): ResultAsync<${r}Detail> => {
|
|
293
|
+
return ${i}.get<${r}Detail>(AppApis.${t}.getById(id));
|
|
294
294
|
},
|
|
295
295
|
|
|
296
|
-
create: (data: Create${
|
|
297
|
-
return ${i}.post<${
|
|
296
|
+
create: (data: Create${r}Dto): ResultAsync<${r}Detail> => {
|
|
297
|
+
return ${i}.post<${r}Detail>(AppApis.${t}.create, data);
|
|
298
298
|
},
|
|
299
299
|
|
|
300
|
-
update: (id: string, data: Update${
|
|
301
|
-
return ${i}.patch<${
|
|
300
|
+
update: (id: string, data: Update${r}Dto): ResultAsync<${r}Detail> => {
|
|
301
|
+
return ${i}.patch<${r}Detail>(AppApis.${t}.update(id), data);
|
|
302
302
|
},
|
|
303
303
|
|
|
304
304
|
delete: (id: string): ResultAsync<void> => {
|
|
305
|
-
return ${i}.delete<void>(AppApis.${
|
|
305
|
+
return ${i}.delete<void>(AppApis.${t}.delete(id));
|
|
306
306
|
},
|
|
307
307
|
};
|
|
308
|
-
`},
|
|
309
|
-
base: \`\${API_PREFIX}/${
|
|
310
|
-
getAll: \`\${API_PREFIX}/${
|
|
311
|
-
getById: (id: string) => \`\${API_PREFIX}/${
|
|
312
|
-
create: \`\${API_PREFIX}/${
|
|
313
|
-
update: (id: string) => \`\${API_PREFIX}/${
|
|
314
|
-
delete: (id: string) => \`\${API_PREFIX}/${
|
|
315
|
-
},`};var
|
|
316
|
-
${
|
|
308
|
+
`},Tn=e=>{let{camelName:t,kebabName:r}=e;return` ${t}: {
|
|
309
|
+
base: \`\${API_PREFIX}/${r}\`,
|
|
310
|
+
getAll: \`\${API_PREFIX}/${r}\`,
|
|
311
|
+
getById: (id: string) => \`\${API_PREFIX}/${r}/\${id}\`,
|
|
312
|
+
create: \`\${API_PREFIX}/${r}\`,
|
|
313
|
+
update: (id: string) => \`\${API_PREFIX}/${r}/\${id}\`,
|
|
314
|
+
delete: (id: string) => \`\${API_PREFIX}/${r}/\${id}\`,
|
|
315
|
+
},`};var Xt=async e=>{let{name:t,outputPath:r,httpClient:n}=e,o=O(t),i=R(t);await aa(ca.join(r,`${t}.service.ts`),Cn({camelName:o,pascalName:i,httpClient:n}))};import{mkdir as da,writeFile as yt}from"node:fs/promises";import W from"node:path";import{writeFile as pa}from"node:fs/promises";import la from"node:path";var En=e=>{let{camelName:t,httpClient:r}=e;return`import { AppApis } from '@/lib/config';
|
|
316
|
+
${r==="axios"?"import { axiosClient } from '@/lib/utils/http';":"import { fetchClient } from '@/lib/utils/http';"}
|
|
317
317
|
import type { ResultAsync } from '@/types';
|
|
318
318
|
|
|
319
|
-
export const ${
|
|
319
|
+
export const ${t}Service = {
|
|
320
320
|
getAll: (): ResultAsync<string> => {
|
|
321
|
-
return ${
|
|
321
|
+
return ${r==="axios"?"axiosClient":"fetchClient"}.get<string>(AppApis.${t}.getAll);
|
|
322
322
|
},
|
|
323
323
|
};
|
|
324
|
-
`};var
|
|
325
|
-
export * from './${
|
|
326
|
-
export * from './${
|
|
324
|
+
`};var Le=async e=>{let{name:t,outputPath:r,httpClient:n}=e,o=O(t);await pa(la.join(r,`${t}.service.ts`),En({camelName:o,httpClient:n}))};import{mkdir as ma,writeFile as Me}from"node:fs/promises";import Ge from"node:path";var bn=e=>{let{sliceName:t,withPersist:r}=e;return`export * from './${t}.slice';
|
|
325
|
+
export * from './${t}.selectors';
|
|
326
|
+
export * from './${t}.types';${r?`
|
|
327
327
|
export * from './persist';`:""}
|
|
328
|
-
`},
|
|
328
|
+
`},Rn=e=>{let{featureName:t,componentName:r,hookName:n,withStore:o,withService:i}=e;return`export { default as ${r} } from './components/${r}';
|
|
329
329
|
export { ${n} } from './hooks/${n}';
|
|
330
|
-
export * from './types/${
|
|
330
|
+
export * from './types/${t}.types';${o?`
|
|
331
331
|
export * from './store';`:""}${i?`
|
|
332
|
-
export * from './services/${
|
|
333
|
-
`};var
|
|
332
|
+
export * from './services/${t}.service';`:""}
|
|
333
|
+
`};var $n=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e,o=`${r.toUpperCase()}_PERSIST_VERSION`;return`import { createMigrate, type PersistConfig, type PersistedState } from 'redux-persist';
|
|
334
334
|
import storage from '@/store/storage';
|
|
335
|
-
import type { ${
|
|
335
|
+
import type { ${t}State } from '${n}';
|
|
336
336
|
|
|
337
337
|
const ${o} = 1;
|
|
338
338
|
|
|
339
339
|
const migrations = {
|
|
340
|
-
// Bump ${o} and add a migration here when ${
|
|
340
|
+
// Bump ${o} and add a migration here when ${t}State's
|
|
341
341
|
// shape changes. Receives the previously-persisted state, returns the new
|
|
342
342
|
// shape. Returning \`undefined\` discards stale state.
|
|
343
343
|
// 2: (state) => ({ ...state, newField: defaultValue }),
|
|
344
344
|
} satisfies Record<number, (state: PersistedState) => PersistedState>;
|
|
345
345
|
|
|
346
|
-
export const ${
|
|
347
|
-
key: '${
|
|
346
|
+
export const ${r}PersistConfig: PersistConfig<${t}State> = {
|
|
347
|
+
key: '${r}',
|
|
348
348
|
storage,
|
|
349
349
|
version: ${o},
|
|
350
350
|
// whitelist: ['someField'], // Specify which fields to persist
|
|
351
351
|
migrate: createMigrate(migrations, { debug: false }),
|
|
352
352
|
};
|
|
353
|
-
`};var
|
|
353
|
+
`};var In=e=>{let{componentName:t,camelName:r,sliceName:n}=e;return`import { RootState } from '@/store/rootReducer';
|
|
354
354
|
|
|
355
|
-
export const select${
|
|
355
|
+
export const select${t}State = (state: RootState) => state.${r};
|
|
356
356
|
export { setLoading, setError, resetState } from './${n}.slice';
|
|
357
|
-
`};var
|
|
358
|
-
import type { ${
|
|
357
|
+
`};var Nn=e=>{let{componentName:t,camelName:r,typesImportPath:n}=e;return`import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
|
|
358
|
+
import type { ${t}State } from '${n}';
|
|
359
359
|
|
|
360
|
-
const initialState: ${
|
|
360
|
+
const initialState: ${t}State = {
|
|
361
361
|
loading: false,
|
|
362
362
|
error: null,
|
|
363
363
|
// Add your initial state here
|
|
364
364
|
};
|
|
365
365
|
|
|
366
|
-
export const ${
|
|
367
|
-
name: '${
|
|
366
|
+
export const ${r}Slice = createSlice({
|
|
367
|
+
name: '${r}',
|
|
368
368
|
initialState,
|
|
369
369
|
reducers: {
|
|
370
370
|
setLoading: (state, action: PayloadAction<boolean>) => {
|
|
@@ -380,37 +380,37 @@ export const ${t}Slice = createSlice({
|
|
|
380
380
|
},
|
|
381
381
|
});
|
|
382
382
|
|
|
383
|
-
export const { setLoading, setError, resetState } = ${
|
|
383
|
+
export const { setLoading, setError, resetState } = ${r}Slice.actions;
|
|
384
384
|
|
|
385
|
-
export const ${
|
|
386
|
-
`};var
|
|
387
|
-
${
|
|
385
|
+
export const ${r}Reducer = ${r}Slice.reducer;
|
|
386
|
+
`};var ht=e=>{let{componentName:t,withStore:r}=e;return`export interface ${t}State {
|
|
387
|
+
${r?`loading: boolean;
|
|
388
388
|
error: string | null;
|
|
389
389
|
// Add your state properties here`:`// Add your state properties here
|
|
390
390
|
// example: value: string;`}
|
|
391
391
|
}
|
|
392
|
-
`};var
|
|
393
|
-
import { ${
|
|
392
|
+
`};var He=async e=>{let{name:t,outputPath:r,persist:n,typesImportPath:o=`./${t}.types`}=e;await ma(r,{recursive:!0});let i=R(t),s=O(t);await Promise.all([Me(Ge.join(r,`${t}.types.ts`),ht({componentName:i,withStore:!0})),Me(Ge.join(r,`${t}.slice.ts`),Nn({componentName:i,camelName:s,typesImportPath:o})),Me(Ge.join(r,`${t}.selectors.ts`),In({componentName:i,camelName:s,sliceName:t})),...n?[Me(Ge.join(r,"persist.ts"),$n({componentName:i,camelName:s,typesImportPath:o}))]:[],Me(Ge.join(r,"index.ts"),bn({sliceName:t,withPersist:n}))])};var kn=e=>{let{componentName:t,hookName:r}=e;return`'use client';
|
|
393
|
+
import { ${r} } from '../hooks/${r}';
|
|
394
394
|
|
|
395
|
-
export function ${
|
|
396
|
-
const {} = ${
|
|
395
|
+
export function ${t}() {
|
|
396
|
+
const {} = ${r}();
|
|
397
397
|
|
|
398
398
|
return (
|
|
399
399
|
<div>
|
|
400
|
-
<h2>${
|
|
400
|
+
<h2>${t} Component</h2>
|
|
401
401
|
{/* Add your component UI here */}
|
|
402
402
|
</div>
|
|
403
403
|
);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
export default ${
|
|
407
|
-
`};var
|
|
406
|
+
export default ${t};
|
|
407
|
+
`};var An=e=>{let{hookName:t,componentName:r,featureName:n}=e;return`'use client';
|
|
408
408
|
import { useAppDispatch, useAppSelector } from '@/store/hooks';
|
|
409
|
-
import { select${
|
|
409
|
+
import { select${r}State, setLoading, setError } from '../store/${n}.selectors';
|
|
410
410
|
|
|
411
|
-
export const ${
|
|
411
|
+
export const ${t} = () => {
|
|
412
412
|
const dispatch = useAppDispatch();
|
|
413
|
-
const state = useAppSelector(select${
|
|
413
|
+
const state = useAppSelector(select${r}State);
|
|
414
414
|
|
|
415
415
|
const handleSetLoading = (loading: boolean) => {
|
|
416
416
|
dispatch(setLoading(loading));
|
|
@@ -426,10 +426,10 @@ export const ${r} = () => {
|
|
|
426
426
|
setError: handleSetError,
|
|
427
427
|
} as const;
|
|
428
428
|
};
|
|
429
|
-
`},
|
|
429
|
+
`},On=e=>{let{hookName:t}=e;return`'use client';
|
|
430
430
|
import { useState } from 'react';
|
|
431
431
|
|
|
432
|
-
export const ${
|
|
432
|
+
export const ${t} = () => {
|
|
433
433
|
// Add your state and logic here
|
|
434
434
|
const [state, setState] = useState({});
|
|
435
435
|
|
|
@@ -438,8 +438,8 @@ export const ${r} = () => {
|
|
|
438
438
|
// Add your methods here
|
|
439
439
|
} as const;
|
|
440
440
|
};
|
|
441
|
-
`};var
|
|
442
|
-
`)};var
|
|
441
|
+
`};var Wt=async e=>{let{name:t,outputPath:r,createStore:n,persistStore:o,createService:i,httpClient:s}=e,a=R(t),p=`use${a}`,d=[W.join(r,"components"),W.join(r,"hooks"),W.join(r,"types"),...n?[W.join(r,"store")]:[],...i?[W.join(r,"services")]:[]];await Promise.all(d.map(u=>da(u,{recursive:!0}))),await Promise.all([yt(W.join(r,"components",`${a}.tsx`),kn({componentName:a,hookName:p})),yt(W.join(r,"hooks",`${p}.ts`),n?An({hookName:p,componentName:a,featureName:t}):On({hookName:p})),yt(W.join(r,"types",`${t}.types.ts`),ht({componentName:a,withStore:n})),yt(W.join(r,"index.ts"),Rn({featureName:t,componentName:a,hookName:p,withStore:n,withService:i}))]),n&&await He({name:t,outputPath:W.join(r,"store"),persist:o,typesImportPath:`../types/${t}.types`}),i&&s&&await Le({name:t,outputPath:W.join(r,"services"),httpClient:s})};import{mkdir as ua,writeFile as fa}from"node:fs/promises";import Yt from"node:path";var Fn=e=>{let{hookName:t,isClient:r}=e,n=[];return r&&n.push("'use client';"),n.push("import { useState, useCallback } from 'react';"),n.push(""),n.push(`export const ${t} = () => {`),n.push(" const [loading, setLoading] = useState(false);"),n.push(" const [error, setError] = useState<string | null>(null);"),n.push(""),n.push(" const execute = useCallback(async () => {"),n.push(" setLoading(true);"),n.push(" setError(null);"),n.push(" try {"),n.push(" // Add your logic here"),n.push(" } catch (err) {"),n.push(" setError(err instanceof Error ? err.message : 'An error occurred');"),n.push(" } finally {"),n.push(" setLoading(false);"),n.push(" }"),n.push(" }, []);"),n.push(""),n.push(" return {"),n.push(" loading,"),n.push(" error,"),n.push(" execute,"),n.push(" } as const;"),n.push("};"),n.push(""),n.join(`
|
|
442
|
+
`)};var Kt=async e=>{let{name:t,projectPath:r,isClient:n,featurePath:o}=e,s=`use${R(t)}`,a;o?a=Yt.join(r,o,"hooks"):a=Yt.join(r,"src","hooks"),await ua(a,{recursive:!0}),await fa(Yt.join(a,`${s}.ts`),Fn({hookName:s,isClient:n}))};import{mkdir as ya}from"node:fs/promises";import xt from"node:path";P();var ga=e=>`import { setRequestLocale } from 'next-intl/server';
|
|
443
443
|
import type { SupportedLocale } from '@/types/i18n';
|
|
444
444
|
|
|
445
445
|
type Props = {
|
|
@@ -453,21 +453,21 @@ export default async function ${e}({ children, params }: Props) {
|
|
|
453
453
|
|
|
454
454
|
return <>{children}</>;
|
|
455
455
|
}
|
|
456
|
-
`,
|
|
456
|
+
`,ha=e=>`type Props = {
|
|
457
457
|
children: React.ReactNode;
|
|
458
458
|
};
|
|
459
459
|
|
|
460
460
|
export default function ${e}({ children }: Props) {
|
|
461
461
|
return <>{children}</>;
|
|
462
462
|
}
|
|
463
|
-
`,
|
|
464
|
-
`)}},
|
|
465
|
-
name: '${
|
|
466
|
-
locale: '${
|
|
463
|
+
`,_n=({componentName:e,hasI18n:t})=>t?ga(e):ha(e);var xa=/^[a-z][a-z0-9-]*$/,Pa=/^[a-z][a-z0-9-]*(\/[a-z][a-z0-9-]*)*$/,va=e=>{if(!xa.test(e))throw new Error(`Invalid layout segment "${e}". Use kebab-case letters, digits, and hyphens. For route groups pass --group instead of wrapping in parens.`)},wa=e=>{if(!Pa.test(e))throw new Error(`Invalid --at path "${e}". Use kebab-case segments separated by "/", e.g. "dashboard/settings".`)},Zt=async e=>{let{segment:t,at:r,projectPath:n,hasI18n:o,withGroup:i}=e;va(t),r&&wa(r);let s=`${R(t)}Layout`,a=i?`(${t})`:t,p=["src","app"];o&&p.push("[locale]"),r&&p.push(...r.split("/")),p.push(a);let d=xt.join(n,...p),u=xt.join(d,"layout.tsx");if(m(u))throw new Error(`Layout already exists at ${xt.relative(n,u)}.`);return await ya(d,{recursive:!0}),await g(u,_n({componentName:s,hasI18n:o})),{layoutFile:u,displayPath:xt.relative(n,u),componentName:s}};P();import{copyFile as Sa,readFile as Ca,writeFile as Ta}from"node:fs/promises";import Ue from"node:path";var Qt=async e=>{let{code:t,name:r,country:n,flag:o,projectPath:i,copyTranslations:s}=e;await Ea(i,t,s),await ba(i,t),await Ra(i,t,r,n,o)},Ea=async(e,t,r)=>{let n=Ue.join(e,"src","i18n","translations"),o=Ue.join(n,"en.json"),i=Ue.join(n,`${t}.json`);if(r)await Sa(o,i);else{let s=await Ca(o,"utf-8"),a=JSON.parse(s),p=jn(a);await Ta(i,`${JSON.stringify(p,null,2)}
|
|
464
|
+
`)}},jn=e=>{let t={};for(let[r,n]of Object.entries(e))typeof n=="object"&&n!==null?t[r]=jn(n):t[r]="";return t},ba=async(e,t)=>{let r=Ue.join(e,"src","types","i18n.ts");if(!m(r))return;let n=await f(r),o=/export type SupportedLocale = (.*);/,i=n.match(o);if(i&&!i[1].includes(`'${t}'`)){let s=`${i[1]} | '${t}'`;n=n.replace(o,`export type SupportedLocale = ${s};`),await g(r,n)}},Ra=async(e,t,r,n,o)=>{let i=Ue.join(e,"src","lib","config","app-locales.ts");if(!m(i))return;let s=await f(i);if(s.includes(`locale: '${t}'`))return;let a=s.lastIndexOf("];");if(a===-1)return;let p=` {
|
|
465
|
+
name: '${r}',
|
|
466
|
+
locale: '${t}',
|
|
467
467
|
flag: '${o}',
|
|
468
468
|
country: '${n}',
|
|
469
469
|
},
|
|
470
|
-
`;s=s.slice(0,a)+p+s.slice(a),await
|
|
470
|
+
`;s=s.slice(0,a)+p+s.slice(a),await g(i,s)};import{mkdir as $a,writeFile as er}from"node:fs/promises";import ze from"node:path";var Dn=e=>{let{componentName:t,routePath:r,hasI18n:n}=e;return n?`import { generateSEOMetadata } from '@/lib/config/seo';
|
|
471
471
|
import type { Metadata } from 'next';
|
|
472
472
|
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
|
473
473
|
import type { SupportedLocale } from '@/types/i18n';
|
|
@@ -478,20 +478,20 @@ type Props = {
|
|
|
478
478
|
|
|
479
479
|
export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
480
480
|
const locale = (await props.params).locale as SupportedLocale;
|
|
481
|
-
const t = await getTranslations({ locale, namespace: '${
|
|
481
|
+
const t = await getTranslations({ locale, namespace: '${t}' });
|
|
482
482
|
|
|
483
483
|
return generateSEOMetadata({
|
|
484
484
|
title: t('title'),
|
|
485
485
|
description: t('description'),
|
|
486
|
-
path: '${
|
|
486
|
+
path: '${r}',
|
|
487
487
|
});
|
|
488
488
|
}
|
|
489
489
|
|
|
490
|
-
export default async function ${
|
|
490
|
+
export default async function ${t}Page(props: Props) {
|
|
491
491
|
const locale = (await props.params).locale as SupportedLocale;
|
|
492
492
|
setRequestLocale(locale);
|
|
493
493
|
|
|
494
|
-
const t = await getTranslations('${
|
|
494
|
+
const t = await getTranslations('${t}');
|
|
495
495
|
|
|
496
496
|
return (
|
|
497
497
|
<div>
|
|
@@ -502,29 +502,29 @@ export default async function ${r}Page(props: Props) {
|
|
|
502
502
|
`:`import type { Metadata } from 'next';
|
|
503
503
|
|
|
504
504
|
export const metadata: Metadata = {
|
|
505
|
-
title: '${
|
|
506
|
-
description: '${
|
|
505
|
+
title: '${t}',
|
|
506
|
+
description: '${t} page',
|
|
507
507
|
};
|
|
508
508
|
|
|
509
|
-
export default function ${
|
|
509
|
+
export default function ${t}Page() {
|
|
510
510
|
return (
|
|
511
511
|
<div>
|
|
512
|
-
<h1>${
|
|
512
|
+
<h1>${t}</h1>
|
|
513
513
|
</div>
|
|
514
514
|
);
|
|
515
515
|
}
|
|
516
|
-
`},
|
|
516
|
+
`},Ln=e=>{let{componentName:t,paramName:r,routePath:n,hasI18n:o}=e;return o?`import { generateSEOMetadata } from '@/lib/config/seo';
|
|
517
517
|
import type { Metadata } from 'next';
|
|
518
518
|
import { getTranslations, setRequestLocale } from 'next-intl/server';
|
|
519
519
|
import type { SupportedLocale } from '@/types/i18n';
|
|
520
520
|
|
|
521
521
|
type Props = {
|
|
522
|
-
params: Promise<{ locale: string; ${
|
|
522
|
+
params: Promise<{ locale: string; ${r}: string }>;
|
|
523
523
|
};
|
|
524
524
|
|
|
525
525
|
export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
526
|
-
const { locale, ${
|
|
527
|
-
const t = await getTranslations({ locale: locale as SupportedLocale, namespace: '${
|
|
526
|
+
const { locale, ${r} } = await props.params;
|
|
527
|
+
const t = await getTranslations({ locale: locale as SupportedLocale, namespace: '${t}' });
|
|
528
528
|
|
|
529
529
|
return generateSEOMetadata({
|
|
530
530
|
title: t('title'),
|
|
@@ -533,48 +533,48 @@ export async function generateMetadata(props: Props): Promise<Metadata> {
|
|
|
533
533
|
});
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
-
export default async function ${
|
|
537
|
-
const { locale, ${
|
|
536
|
+
export default async function ${t}Page(props: Props) {
|
|
537
|
+
const { locale, ${r} } = await props.params;
|
|
538
538
|
setRequestLocale(locale);
|
|
539
539
|
|
|
540
|
-
const t = await getTranslations('${
|
|
540
|
+
const t = await getTranslations('${t}');
|
|
541
541
|
|
|
542
542
|
return (
|
|
543
543
|
<div>
|
|
544
544
|
<h1>{t('title')}</h1>
|
|
545
|
-
<p>${
|
|
545
|
+
<p>${t}: {${r}}</p>
|
|
546
546
|
</div>
|
|
547
547
|
);
|
|
548
548
|
}
|
|
549
549
|
`:`import type { Metadata } from 'next';
|
|
550
550
|
|
|
551
551
|
export const metadata: Metadata = {
|
|
552
|
-
title: '${
|
|
553
|
-
description: '${
|
|
552
|
+
title: '${t}',
|
|
553
|
+
description: '${t} page',
|
|
554
554
|
};
|
|
555
555
|
|
|
556
556
|
type Props = {
|
|
557
|
-
params: Promise<{ ${
|
|
557
|
+
params: Promise<{ ${r}: string }>;
|
|
558
558
|
};
|
|
559
559
|
|
|
560
|
-
export default async function ${
|
|
561
|
-
const { ${
|
|
560
|
+
export default async function ${t}Page(props: Props) {
|
|
561
|
+
const { ${r} } = await props.params;
|
|
562
562
|
|
|
563
563
|
return (
|
|
564
564
|
<div>
|
|
565
|
-
<h1>${
|
|
566
|
-
<p>${
|
|
565
|
+
<h1>${t}</h1>
|
|
566
|
+
<p>${t}: {${r}}</p>
|
|
567
567
|
</div>
|
|
568
568
|
);
|
|
569
569
|
}
|
|
570
|
-
`},
|
|
570
|
+
`},Mn=e=>`export default function ${e.componentName}Loading() {
|
|
571
571
|
return (
|
|
572
572
|
<div className="flex h-full items-center justify-center">
|
|
573
573
|
<p>Loading...</p>
|
|
574
574
|
</div>
|
|
575
575
|
);
|
|
576
576
|
}
|
|
577
|
-
`,
|
|
577
|
+
`,Gn=e=>`'use client';
|
|
578
578
|
|
|
579
579
|
export default function ${e.componentName}Error({
|
|
580
580
|
error,
|
|
@@ -591,7 +591,7 @@ export default function ${e.componentName}Error({
|
|
|
591
591
|
</div>
|
|
592
592
|
);
|
|
593
593
|
}
|
|
594
|
-
`;var
|
|
594
|
+
`;var tr=async e=>{let{name:t,projectPath:r,hasI18n:n,dynamic:o,withLoading:i=!1,withError:s=!1}=e,a=R(t),p=`/${t}`,d=n?"src/app/[locale]":"src/app",u;o?u=ze.join(r,d,t,`[${o}]`):u=ze.join(r,d,t),await $a(u,{recursive:!0});let h=o?Ln({componentName:a,routePath:o?`${p}/[${o}]`:p,paramName:o,hasI18n:n}):Dn({componentName:a,routePath:p,hasI18n:n});await er(ze.join(u,"page.tsx"),h),i&&await er(ze.join(u,"loading.tsx"),Mn({componentName:a})),s&&await er(ze.join(u,"error.tsx"),Gn({componentName:a}))};S();import{mkdir as Ia}from"node:fs/promises";import rr from"node:path";P();var Hn=(e,t)=>e.endsWith(t)?e:`${e}${t}`,Un=({baseName:e})=>{let t=Hn(e,"Provider"),r=t.replace(/Provider$/,""),n=`${r}ContextValue`,o=`${r}Context`,i=`use${r}`;return`'use client';
|
|
595
595
|
import { createContext, useContext, useMemo } from 'react';
|
|
596
596
|
|
|
597
597
|
type ${n} = {
|
|
@@ -603,52 +603,52 @@ const ${o} = createContext<${n} | null>(null);
|
|
|
603
603
|
export const ${i} = (): ${n} => {
|
|
604
604
|
const ctx = useContext(${o});
|
|
605
605
|
if (!ctx) {
|
|
606
|
-
throw new Error('${i} must be used within ${
|
|
606
|
+
throw new Error('${i} must be used within ${t}');
|
|
607
607
|
}
|
|
608
608
|
return ctx;
|
|
609
609
|
};
|
|
610
610
|
|
|
611
|
-
export const ${
|
|
611
|
+
export const ${t} = ({ children }: { children: React.ReactNode }) => {
|
|
612
612
|
const value = useMemo<${n}>(() => ({}), []);
|
|
613
613
|
return <${o}.Provider value={value}>{children}</${o}.Provider>;
|
|
614
614
|
};
|
|
615
|
-
`}
|
|
615
|
+
`},zn=e=>Hn(e,"Provider");var Na=/^[A-Za-z][A-Za-z0-9-]*$/,ka=e=>e.includes("-")?R(e):e.charAt(0).toUpperCase()+e.slice(1),nr=async e=>{let{name:t,projectPath:r}=e;if(!Na.test(t))throw new Error(`Invalid provider name "${t}". Use kebab-case or PascalCase letters and digits only.`);let n=ka(t).replace(/Provider$/,""),o=zn(n),i=o,s=rr.join(r,c.PROVIDERS),a=rr.join(s,`${i}.tsx`);if(m(a))throw new Error(`Provider already exists at ${rr.relative(r,a)}.`);return await Ia(s,{recursive:!0}),await g(a,Un({baseName:n})),{componentName:o,fileBaseName:i,providerFile:a}};P();import Je from"node:path";var Jn=e=>{let{componentName:t,sourceImportPath:r,testUtilsImportPath:n,hasRedux:o,hasI18n:i}=e,s=[];i&&s.push("messages: {}"),o&&s.push("preloadedState: {}");let a=s.length?`, {
|
|
616
616
|
${s.join(`,
|
|
617
617
|
`)},
|
|
618
618
|
}`:"";return`import { describe, expect, it } from 'vitest';
|
|
619
619
|
import { renderWithProviders, screen } from '${n}';
|
|
620
|
-
import { ${
|
|
620
|
+
import { ${t} } from '${r}';
|
|
621
621
|
|
|
622
|
-
describe('${
|
|
622
|
+
describe('${t}', () => {
|
|
623
623
|
it('renders without crashing', () => {
|
|
624
|
-
renderWithProviders(<${
|
|
624
|
+
renderWithProviders(<${t} />${a});
|
|
625
625
|
// TODO: assert something meaningful about the rendered output.
|
|
626
626
|
expect(screen).toBeDefined();
|
|
627
627
|
});
|
|
628
628
|
});
|
|
629
|
-
`},
|
|
629
|
+
`},Vn=e=>{let{hookName:t,sourceImportPath:r,withStore:n,testUtilsImportPath:o}=e;return n?`import { renderHook } from '@testing-library/react';
|
|
630
630
|
import { describe, expect, it } from 'vitest';
|
|
631
631
|
import { TestProviders } from '${o}';
|
|
632
|
-
import { ${
|
|
632
|
+
import { ${t} } from '${r}';
|
|
633
633
|
|
|
634
|
-
describe('${
|
|
634
|
+
describe('${t}', () => {
|
|
635
635
|
it('returns a defined value', () => {
|
|
636
|
-
const { result } = renderHook(() => ${
|
|
636
|
+
const { result } = renderHook(() => ${t}(), { wrapper: TestProviders });
|
|
637
637
|
expect(result.current).toBeDefined();
|
|
638
638
|
});
|
|
639
639
|
});
|
|
640
640
|
`:`import { renderHook } from '@testing-library/react';
|
|
641
641
|
import { describe, expect, it } from 'vitest';
|
|
642
|
-
import { ${
|
|
642
|
+
import { ${t} } from '${r}';
|
|
643
643
|
|
|
644
|
-
describe('${
|
|
644
|
+
describe('${t}', () => {
|
|
645
645
|
it('returns a defined value', () => {
|
|
646
|
-
const { result } = renderHook(() => ${
|
|
646
|
+
const { result } = renderHook(() => ${t}());
|
|
647
647
|
expect(result.current).toBeDefined();
|
|
648
648
|
});
|
|
649
649
|
});
|
|
650
|
-
`},
|
|
651
|
-
import { ${n}, resetState, setError, setLoading } from '${
|
|
650
|
+
`},Bn=e=>{let{camelName:t,sourceImportPath:r}=e,n=`${t}Slice`;return`import { describe, expect, it } from 'vitest';
|
|
651
|
+
import { ${n}, resetState, setError, setLoading } from '${r}';
|
|
652
652
|
|
|
653
653
|
describe('${n}', () => {
|
|
654
654
|
const initialState = { loading: false, error: null } as const;
|
|
@@ -672,30 +672,30 @@ describe('${n}', () => {
|
|
|
672
672
|
expect(next).toEqual(initialState);
|
|
673
673
|
});
|
|
674
674
|
});
|
|
675
|
-
`};var
|
|
675
|
+
`};var oe=async e=>{let{projectPath:t,sourceFile:r,kind:n,symbolName:o}=e,i=Je.dirname(r),s=Je.basename(r).replace(/\.(tsx?|jsx?)$/i,""),a=n==="component"?".tsx":".ts",p=Je.join(i,`${s}.test${a}`),d=`./${s}`,u=Aa(i,Je.join(t,"test","test-utils")),h;return n==="component"?h=Jn({componentName:o,sourceImportPath:d,testUtilsImportPath:u,hasRedux:!!e.hasRedux,hasI18n:!!e.hasI18n}):n==="hook"?h=Vn({hookName:o,sourceImportPath:d,withStore:!!e.hookUsesStore,testUtilsImportPath:e.hookUsesStore?u:void 0}):h=Bn({camelName:o,sourceImportPath:d}),await g(p,h),p},Aa=(e,t)=>{let r=Je.relative(e,t).replace(/\\/g,"/");return r.startsWith(".")?r:`./${r}`};import Oa from"enquirer";var{prompt:Fa}=Oa,qn=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"componentName",message:"Component name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Component name is required"}),t.client===void 0&&r.push({type:"confirm",name:"isClient",message:"Add 'use client' directive?",initial:!1});let n=r.length>0?await Fa(r):{};return{componentName:e??n.componentName,isClient:t.client??n.isClient??!1}};var Xn=e=>{e.command("component [name]").description("Generate a shared component").option("--client","Add 'use client' directive").option("--i18n","Add useTranslations hook").option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd();l(ee.cyan(`
|
|
676
676
|
\u{1F9E9} Component Generator
|
|
677
|
-
`)),y.start("Detecting project setup...");let o=await
|
|
677
|
+
`)),y.start("Detecting project setup...");let o=await A(n);y.succeed("Project setup detected");let i=await qn(t,{client:r.client}),s=R(i.componentName),a=i.isClient,p=r.i18n??!1,d=_a(r,o.hasTests);y.start("Generating component..."),await qt({name:i.componentName,projectPath:n,isClient:a||p,hasI18n:p,featurePath:r.feature}),y.succeed("Component generated");let u=null;if(d){let x=r.feature?or.join(n,r.feature,"components",`${s}.tsx`):or.join(n,"src/components/common",s,`${s}.tsx`);y.start("Generating test..."),u=await oe({projectPath:n,sourceFile:x,kind:"component",symbolName:s,hasRedux:o.hasRedux,hasI18n:o.hasI18n}),y.succeed("Test generated")}let h=r.feature?`${r.feature}/components/${s}.tsx`:`src/components/common/${s}/${s}.tsx`;l(ee.green(`
|
|
678
678
|
\u2728 Component '${s}' created successfully!
|
|
679
|
-
`)),l(
|
|
679
|
+
`)),l(ee.dim(` \u{1F4C4} ${h}`)),r.feature||(l(ee.dim(` \u{1F4C4} src/components/common/${s}/index.ts`)),l(ee.dim(" \u{1F4DD} Updated src/components/common/index.ts")),l(ee.dim(" \u{1F4DD} Updated src/components/index.ts"))),u&&l(ee.dim(` \u{1F9EA} ${or.relative(n,u)}`)),l(""),l(ee.cyan("Usage:")),r.feature?l(ee.dim(` import { ${s} } from '${r.feature.replace(/^src\//,"@/")}/components/${s}';`)):l(ee.dim(` import { ${s} } from '@/components';`)),l("")}catch(n){y.fail("Component generation failed"),v(`${n}`),process.exit(1)}})},_a=(e,t)=>e.noTest?!1:e.test?!0:t;import L from"picocolors";S();P();import Da from"node:path";S();import Wn from"node:path";import ja from"picocolors";P();var Ve=async e=>{let t=b("Adding @next/bundle-analyzer...");try{let r=Wn.join(e,c.NEXT_CONFIG);if(!m(r))throw new Error(`${c.NEXT_CONFIG} not found.`);let n=await f(r);if(n.includes("@next/bundle-analyzer")){t.fail("@next/bundle-analyzer is already configured.");return}n=`import withBundleAnalyzer from '@next/bundle-analyzer';
|
|
680
680
|
${n}`;let o=/export default (.*?);/,i=n.match(o);if(!i)throw new Error("Could not locate `export default` in next.config.ts.");let a=`const bundleAnalyzer = withBundleAnalyzer({
|
|
681
681
|
enabled: process.env.ANALYZE === 'true',
|
|
682
682
|
});
|
|
683
683
|
|
|
684
|
-
export default bundleAnalyzer(${i[1]});`;n=n.replace(o,a),await
|
|
685
|
-
`),n=[],o=new RegExp(`^import\\s+${
|
|
686
|
-
`)}
|
|
687
|
-
`),n=new RegExp(`^([ \\t]*)<${e}\\b`),o=-1,i="";for(let h=0;h<
|
|
688
|
-
`);return
|
|
684
|
+
export default bundleAnalyzer(${i[1]});`;n=n.replace(o,a),await g(r,n),await F(Wn.join(e,c.PACKAGE_JSON),p=>(p.scripts=p.scripts??{},p.scripts.analyze||(p.scripts.analyze="ANALYZE=true next build"),p)),t.text="Installing @next/bundle-analyzer...",await mt(e,"@next/bundle-analyzer"),t.succeed(ja.green("@next/bundle-analyzer configured."))}catch(r){throw t.fail("Failed to add @next/bundle-analyzer."),r}};var ir=(e,t)=>{let r=e.split(`
|
|
685
|
+
`),n=[],o=new RegExp(`^import\\s+${t}\\s+from\\s+['"][^'"]+['"];?\\s*$`),i=/^(import\s+)\{([^}]+)\}(\s+from\s+['"][^'"]+['"];?\s*)$/;for(let s of r){if(o.test(s))continue;let a=s.match(i);if(a){let p=a[2].split(",").map(u=>u.trim()).filter(Boolean),d=p.filter(u=>u.replace(/^type\s+/,"").split(/\s+as\s+/)[0].trim()!==t);if(d.length===0)continue;if(d.length<p.length){n.push(`${a[1]}{ ${d.join(", ")} }${a[3]}`);continue}}n.push(s)}return n.join(`
|
|
686
|
+
`)},$e=e=>t=>{let r=t.split(`
|
|
687
|
+
`),n=new RegExp(`^([ \\t]*)<${e}\\b`),o=-1,i="";for(let h=0;h<r.length;h++){let x=r[h].match(n);if(x){o=h,i=x[1];break}}if(o===-1||!/>\s*$/.test(r[o]))return null;let s=i.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),a=new RegExp(`^${s}<\\/${e}>\\s*$`),p=-1;for(let h=o+1;h<r.length;h++)if(a.test(r[h])){p=h;break}if(p===-1)return null;let d=r.slice(o+1,p).map(h=>h.startsWith(" ")?h.slice(2):h),u=[...r.slice(0,o),...d,...r.slice(p+1)].join(`
|
|
688
|
+
`);return ir(u,e)};var Yn=e=>{let t=e.split(`
|
|
689
689
|
`).filter(n=>!/^import\s+createNextIntlPlugin\s+from\s+['"]next-intl\/plugin['"];?\s*$/.test(n)).join(`
|
|
690
|
-
`);
|
|
691
|
-
`,
|
|
692
|
-
`,await
|
|
693
|
-
${
|
|
694
|
-
${
|
|
690
|
+
`);t=t.replace(/^const\s+withNextIntl\s*=\s*createNextIntlPlugin\([^)]*\);\s*\n?/m,"");let r=/withNextIntl\(\s*((?:[^()]|\([^()]*\))+?)\s*\)/;return r.test(t)?(t=t.replace(r,"$1"),t):null},Kn=e=>{let t=ir(e,"withBundleAnalyzer"),r=/^const\s+bundleAnalyzer\s*=\s*withBundleAnalyzer\(\{[\s\S]*?\}\);\s*\n?/m;if(!r.test(t))return null;t=t.replace(r,"");let n=/bundleAnalyzer\(\s*((?:[^()]|\([^()]*\))+?)\s*\)/;return n.test(t)?(t=t.replace(n,"$1"),t):null};var Zn={id:"bundle-analyzer",name:"Bundle Analyzer",description:"@next/bundle-analyzer wrapped around the default export",detect:async e=>{let t=Da.join(e,c.NEXT_CONFIG);return m(t)?/@next\/bundle-analyzer/.test(await f(t)):!1},files:[],packages:[{name:"@next/bundle-analyzer",kind:"devDependency"}],scripts:[{name:"analyze",expectedValue:"ANALYZE=true next build"}],injections:[{file:c.NEXT_CONFIG,description:"withBundleAnalyzer import + wrapping",presence:/@next\/bundle-analyzer/,removePattern:Kn}],apply:Ve};S();P();import Ga from"node:path";S();import Qn from"node:path";import La from"picocolors";P();var sr=e=>{let t={...e.scripts??{}},r={...e.devDependencies??{}};return t.commit||(t.commit="cz"),r[C.COMMITIZEN]||(r[C.COMMITIZEN]="*"),r[C.CZ_CONVENTIONAL_CHANGELOG]||(r[C.CZ_CONVENTIONAL_CHANGELOG]="*"),{...e,scripts:t,devDependencies:r}},ar=e=>{let t=e.devDependencies??{},r=[];return t[C.COMMITIZEN]||r.push(C.COMMITIZEN),t[C.CZ_CONVENTIONAL_CHANGELOG]||r.push(C.CZ_CONVENTIONAL_CHANGELOG),r};var Ma=`${JSON.stringify({path:"cz-conventional-changelog"},null,2)}
|
|
691
|
+
`,Be=async e=>{let t=b("Setting up Commitizen...");try{let r=Qn.join(e,c.CZRC);m(r)||await g(r,Ma);let n=Qn.join(e,c.PACKAGE_JSON),o=JSON.parse(await f(n)),i=ar(o);if(await F(n,s=>sr(s)),i.length>0){t.text=`Installing ${i.join(", ")}...`;let s=await _(e);await xe(e,s,i)}t.succeed(La.green("Commitizen configured. Use `commit` to start a guided commit."))}catch(r){throw t.fail("Failed to set up Commitizen."),r}};var eo={id:"commitizen",name:"Commitizen",description:"Guided conventional-commit prompt via `commit` script",detect:async e=>m(Ga.join(e,c.CZRC)),files:[{path:c.CZRC,generated:!0}],packages:[{name:"commitizen",kind:"devDependency"},{name:"cz-conventional-changelog",kind:"devDependency"}],scripts:[{name:"commit",expectedValue:"cz"}],injections:[],apply:Be};S();P();import Ja from"node:path";import Ua from"node:path";import za from"picocolors";P();S();P();import to from"node:path";import Ha from"degit";var ro=async(e,t)=>{t.text="Fetching assets from starter repo...",await Ha("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},no=async(e,t)=>{let r=to.join(e,c.THEME_PROVIDER),n=to.join(t,"src/providers/CustomThemeProvider.tsx");await j(n,r)};S();P();import qe from"node:path";S();P();import oo from"node:path";var Pt=async e=>{let t=[oo.join(e,c.ROOT_LAYOUT),oo.join(e,"src/app/[locale]/layout.tsx")];for(let r of t)if(m(r)&&(await f(r)).includes("<body"))return r;for(let r of t)if(m(r))return r;return""};var io=async e=>{let t=qe.join(e,c.THEME_PROVIDER),r=qe.join(e,c.GLOBALS_CSS),n=qe.join(e,"package.json");if(m(t))return{isSetup:!0,reason:"CustomThemeProvider.tsx exists"};if(m(n)){let o=JSON.parse(await f(n)),i="@teispace/next-themes";if(o.dependencies?.[i]||o.devDependencies?.[i])return{isSetup:!0,reason:`${i} is installed`}}return m(r)&&(await f(r)).includes("@custom-variant dark")?{isSetup:!0,reason:"Dark theme CSS found in globals.css"}:{isSetup:!1,reason:""}},so=async e=>{let t=qe.join(e,c.GLOBALS_CSS),r=qe.join(e,c.PROVIDERS_INDEX),n=await Pt(e);if(!m(t)||!n||!m(r))throw new Error("Project structure mismatch. Ensure src/styles/globals.css, src/app/layout.tsx (or src/app/[locale]/layout.tsx), and src/providers/index.ts exist.");return n};S();P();import vt from"node:path";var ao=async e=>{let t=vt.join(e,c.PROVIDERS_INDEX),r=await f(t);r.includes("CustomThemeProvider")||(r+=`export * from './CustomThemeProvider';
|
|
692
|
+
`,await g(t,r))},co=async e=>{let t=vt.join(e,"src/providers/RootProvider.tsx");if(!m(t))return;let r=await f(t),n="'use client';",o=r.includes(n);if(o&&(r=r.replace(n,"").trim()),r.includes("CustomThemeProvider")||(/import\s*\{[^}]*\}\s*from\s*'@\/providers'/.test(r)?r=r.replace(/(import\s*\{)([^}]*)(\}\s*from\s*'@\/providers')/,(i,s,a,p)=>`${s}${a.trim()?`${a.trim()}, CustomThemeProvider `:" CustomThemeProvider "}${p}`):r=`import { CustomThemeProvider } from '@/providers';
|
|
693
|
+
${r}`),o&&(r=`${n}
|
|
694
|
+
${r}`),!r.includes("<CustomThemeProvider"))if(r.includes("{children}"))r=r.replace(/\{children\}/,"<CustomThemeProvider>{children}</CustomThemeProvider>");else{let i=r.match(/return\s*\(\s*([\s\S]*?)\s*\);/);i&&(r=r.replace(i[0],`return (
|
|
695
695
|
<CustomThemeProvider>
|
|
696
696
|
${i[1]}
|
|
697
697
|
</CustomThemeProvider>
|
|
698
|
-
);`))}await
|
|
698
|
+
);`))}await g(t,r)},po=async(e,t)=>{let r=vt.join(e,c.GLOBALS_CSS),n=vt.join(t,"src/styles/globals.css"),o="";if(m(n)){let s=await f(n),a=s.match(/@custom-variant dark \(.*?\);/),p=s.match(/@theme \{[\s\S]*?\}/);a&&(o+=`
|
|
699
699
|
${a[0]}
|
|
700
700
|
`),p&&(o+=`
|
|
701
701
|
${p[0]}
|
|
@@ -706,50 +706,50 @@ ${p[0]}
|
|
|
706
706
|
--color-dark: #202938;
|
|
707
707
|
--color-light: #f5f5f5;
|
|
708
708
|
}
|
|
709
|
-
`);let i=await
|
|
710
|
-
`,s);i=i.slice(0,a+1)+o+i.slice(a+1)}else i=o+i;await
|
|
709
|
+
`);let i=await f(r);if(!i.includes("@custom-variant dark")){if(i.includes("@import")){let s=i.lastIndexOf("@import"),a=i.indexOf(`
|
|
710
|
+
`,s);i=i.slice(0,a+1)+o+i.slice(a+1)}else i=o+i;await g(r,i)}},lo=async e=>{let t=await f(e);t.includes("dark:bg-dark")||(t=t.replace(/className="([^"]*)"/,'className="$1 bg-light dark:bg-dark"'),await g(e,t))};var Xe=async e=>{let t=b("Setting up Dark Theme..."),r=Ua.join(e,".next-maker-temp");try{let{isSetup:n,reason:o}=await io(e);if(n){t.fail(`Dark Theme is already set up (${o}).`);return}let i=await so(e);await ro(r,t),await no(e,r),await ao(e),await co(e),await po(e,r),await lo(i),t.text="Installing @teispace/next-themes...",await q(e,"@teispace/next-themes"),t.text="Formatting code...";let s=await _(e);await B(e,s,"lint:fix"),t.succeed(za.green("Dark Theme setup successfully!"))}catch(n){throw t.fail("Failed to setup Dark Theme."),n}finally{await w(r)}};var mo={id:"dark-theme",name:"Dark Theme",description:"@teispace/next-themes + CustomThemeProvider",detect:async e=>m(Ja.join(e,c.THEME_PROVIDER)),files:[{path:c.THEME_PROVIDER,generated:!0}],packages:[{name:"@teispace/next-themes",kind:"dependency"}],scripts:[],injections:[{file:"src/providers/RootProvider.tsx",description:"<CustomThemeProvider> wrap",presence:/CustomThemeProvider/,removePattern:$e("CustomThemeProvider")}],apply:Xe};import Ba from"node:fs/promises";import wt from"node:path";import St from"enquirer";import cr from"picocolors";P();S();P();import ie from"node:fs/promises";import E from"node:path";import Va from"degit";var uo=async(e,t)=>{t.text="Downloading assets from starter repository...",await Va("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},fo=async(e,t,r,n)=>{let o=E.join(e,c.HTTP_UTILS),i=E.join(t,c.HTTP_UTILS);await ie.cp(E.join(t,c.ERRORS_DIR),E.join(e,c.ERRORS_DIR),{recursive:!0});let s=E.join(e,c.APP_APIS);m(s)||await j(E.join(t,c.APP_APIS),s);let a=E.join(e,c.CONSTANTS);if(!m(a))await j(E.join(t,c.CONSTANTS),a);else{let d=await f(a),u=!1;d.includes("API_RESPONSE_DATA_KEY")||(d+=`
|
|
711
711
|
export const API_RESPONSE_DATA_KEY = 'data';
|
|
712
|
-
`,
|
|
712
|
+
`,u=!0),d.includes("SAVE_AUTH_TOKENS")||(d+=`
|
|
713
713
|
export const SAVE_AUTH_TOKENS = false;
|
|
714
|
-
`,
|
|
714
|
+
`,u=!0),u&&await g(a,d)}let p=E.join(e,c.STORAGE_SERVICE);if(m(p)||await ie.cp(E.join(t,c.STORAGE_SERVICE),p,{recursive:!0}),await ie.cp(E.join(t,c.COMMON_TYPES_DIR),E.join(e,c.COMMON_TYPES_DIR),{recursive:!0}),await ie.cp(E.join(t,c.UTILITY_TYPES_DIR),E.join(e,c.UTILITY_TYPES_DIR),{recursive:!0}),await j(E.join(i,"token-store.ts"),E.join(o,"token-store.ts")),await j(E.join(i,"client-utils.ts"),E.join(o,"client-utils.ts")),n&&n.length>0)for(let d of n){let u=E.join(e,d==="fetch"?c.FETCH_CLIENT:c.AXIOS_CLIENT);await w(u)}for(let d of r)d==="fetch"?await ie.cp(E.join(t,c.FETCH_CLIENT),E.join(e,c.FETCH_CLIENT),{recursive:!0}):await ie.cp(E.join(t,c.AXIOS_CLIENT),E.join(e,c.AXIOS_CLIENT),{recursive:!0});await j(E.join(i,"index.ts"),E.join(o,"index.ts")),await j(E.join(t,c.HTTP_TYPES),E.join(e,c.HTTP_TYPES))},go=async e=>{let{isFileUsed:t,isStringUsed:r}=await Promise.resolve().then(()=>(dt(),Kr));await w(E.join(e,c.HTTP_UTILS));let n=E.join(e,c.STORAGE_SERVICE);m(n)&&(await r(e,"SecureStorageService",[n])||await w(n));let o=E.join(e,c.CONSTANTS);if(m(o)){let p=await f(o),d=!1;await r(e,"API_RESPONSE_DATA_KEY",[o])||(p=p.replace(/export const API_RESPONSE_DATA_KEY = .*;\n?/g,""),d=!0),await r(e,"SAVE_AUTH_TOKENS",[o])||(p=p.replace(/export const SAVE_AUTH_TOKENS = .*;\n?/g,""),d=!0),d&&(p=`${p.replace(/\n\s*\n/g,`
|
|
715
715
|
|
|
716
716
|
`).trim()}
|
|
717
|
-
`,await
|
|
718
|
-
${
|
|
719
|
-
`)}`)};
|
|
720
|
-
${
|
|
717
|
+
`,await g(o,p))}let i=E.join(e,c.ERRORS_DIR);if(m(i)){let p=await ie.readdir(i),d=!1;for(let u of p){let h=E.parse(u).name;if(await t(e,h,[E.join(i,u)])){d=!0;break}}d||await w(i)}let s=E.join(e,c.COMMON_TYPES_DIR);m(s)&&(await ie.readdir(s)).length===0&&await w(s);let a=E.join(e,c.UTILITY_TYPES_DIR);m(a)&&(await ie.readdir(a)).length===0&&await w(a)};S();P();import We from"node:path";var ho=async e=>{let t=We.join(e,c.FETCH_CLIENT_FILE),r=We.join(e,c.AXIOS_CLIENT_FILE),n=m(t),o=m(r);return n&&o?{status:"both",reason:"Both Fetch and Axios clients are detected"}:n?{status:"fetch",reason:"Fetch client is already setup"}:o?{status:"axios",reason:"Axios client is already setup"}:{status:"none"}},yo=async e=>{let r=[We.join(e,"src/lib"),We.join(e,"src/types"),We.join(e,"src/lib/config")].filter(n=>!m(n));if(r.length>0)throw new Error(`Invalid project structure. Missing directories:
|
|
718
|
+
${r.map(n=>`- ${n}`).join(`
|
|
719
|
+
`)}`)};dt();var Ye=async e=>{let t=b("Checking HTTP Client setup..."),r=wt.join(e,".next-maker-temp-http");try{let{status:n,reason:o}=await ho(e);t.stop();let i=await qa(n,o);if(i.type==="cancel"){console.log(cr.yellow("Setup cancelled."));return}if(t.start("Setting up HTTP client(s)..."),await yo(e),await uo(r,t),i.type==="replace"&&i.fromClient&&(t.text="Migrating client usages...",await Mt(e,i.fromClient,i.clients[0])),i.type!=="remove-both"&&i.type!=="remove-one"){t.text="Copying client files...";let k=i.type==="replace"&&i.fromClient?[i.fromClient]:void 0;await fo(e,r,i.clients,k)}if(i.type==="remove-one"||i.type==="remove-both"){t.text="Removing client files...";let{PROJECT_PATHS:k}=await Promise.resolve().then(()=>(S(),qr));for(let $ of i.clients){let J=wt.join(e,$==="fetch"?k.FETCH_CLIENT:k.AXIOS_CLIENT);await w(J)}xo(n,i).length===0&&(t.text="Performing full cleanup...",await go(e),await Gt(e))}let s=xo(n,i);s.length>0&&(t.text="Configuring client...",await _t(e,s),await jt(e),await Dt(e),await Lt(e)),await Re(e,s),t.text="Managing dependencies...";let a=wt.join(e,"package.json"),p=JSON.parse(await Ba.readFile(a,"utf-8")),d={...p.dependencies,...p.devDependencies};s.includes("axios")?d.axios||(t.text="Installing Axios...",await q(e,"axios")):d.axios&&(t.text="Uninstalling Axios...",await Ot(e,"axios"));let u=wt.join(e,"src/services/storage");s.length>0||m(u)?d["react-secure-storage"]||(t.text="Installing react-secure-storage...",await q(e,"react-secure-storage")):d["react-secure-storage"]&&(t.text="Uninstalling react-secure-storage...",await Ot(e,"react-secure-storage")),t.text="Formatting code...";let x=await _(e);await B(e,x,"lint:fix"),t.succeed(cr.green(Xa(i)))}catch(n){throw t.fail("Failed to setup HTTP Client."),n}finally{await w(r)}};async function qa(e,t){if(e==="none"){let{choice:n}=await St.prompt({type:"select",name:"choice",message:"Which HTTP client(s) do you want to setup?",choices:[{name:"fetch",message:"Fetch (Native)"},{name:"axios",message:"Axios"},{name:"both",message:"Both (Fetch + Axios)"}]});return n==="both"?{type:"install",clients:["fetch","axios"]}:{type:"install",clients:[n]}}if(e==="fetch"){let{action:n}=await St.prompt({type:"select",name:"action",message:`${t}. What would you like to do?`,choices:[{name:"cancel",message:"Keep Fetch only (cancel)"},{name:"add",message:"Add Axios (have both)"},{name:"replace",message:"Replace with Axios only"},{name:"remove",message:"Remove Fetch"}]});if(n==="cancel")return{type:"cancel",clients:[]};if(n==="add")return{type:"add",clients:["axios"]};if(n==="replace")return{type:"replace",clients:["axios"],fromClient:"fetch"};if(n==="remove")return{type:"remove-one",clients:["fetch"]}}if(e==="axios"){let{action:n}=await St.prompt({type:"select",name:"action",message:`${t}. What would you like to do?`,choices:[{name:"cancel",message:"Keep Axios only (cancel)"},{name:"add",message:"Add Fetch (have both)"},{name:"replace",message:"Replace with Fetch only"},{name:"remove",message:"Remove Axios"}]});if(n==="cancel")return{type:"cancel",clients:[]};if(n==="add")return{type:"add",clients:["fetch"]};if(n==="replace")return{type:"replace",clients:["fetch"],fromClient:"axios"};if(n==="remove")return{type:"remove-one",clients:["axios"]}}console.log(cr.yellow(`\u2716 ${t}`));let{action:r}=await St.prompt({type:"select",name:"action",message:"What would you like to do?",choices:[{name:"cancel",message:"Keep both (cancel)"},{name:"remove-fetch",message:"Remove Fetch (keep Axios)"},{name:"remove-axios",message:"Remove Axios (keep Fetch)"},{name:"remove-both",message:"Remove both"}]});return r==="cancel"?{type:"cancel",clients:[]}:r==="remove-fetch"?{type:"remove-one",clients:["fetch"]}:r==="remove-axios"?{type:"remove-one",clients:["axios"]}:r==="remove-both"?{type:"remove-both",clients:["fetch","axios"]}:{type:"cancel",clients:[]}}function xo(e,t){return t.type==="install"?t.clients:t.type==="add"?[...e==="fetch"?["fetch"]:["axios"],...t.clients]:t.type==="replace"?t.clients:t.type==="remove-one"?e==="both"?t.clients[0]==="fetch"?["axios"]:["fetch"]:[]:[]}function Xa(e){if(e.type==="install")return`HTTP Client (${e.clients.map(r=>r==="fetch"?"Fetch":"Axios").join(" + ")}) setup successfully!`;if(e.type==="add")return`${e.clients[0]==="fetch"?"Fetch":"Axios"} client added successfully! Both clients are now available.`;if(e.type==="replace"){let t=e.fromClient==="fetch"?"Fetch":"Axios",r=e.clients[0]==="fetch"?"Fetch":"Axios";return`Replaced ${t} with ${r} successfully! Imports automatically migrated.`}return e.type==="remove-one"?`${e.clients[0]==="fetch"?"Fetch":"Axios"} client removed successfully!`:e.type==="remove-both"?"Both HTTP clients removed successfully!":"HTTP Client setup completed!"}var Po={id:"http-client",name:"HTTP Client",description:"Axios and/or Fetch client utilities",detect:async e=>{let{detectProjectSetup:t}=await Promise.resolve().then(()=>(G(),De));return(await t(e)).httpClient!=="none"},files:[{path:"src/lib/utils/http",generated:!0,isDir:!0,containsUserContent:!0,removeHint:"holds the http client + any service modules you wired through it \u2014 review before deleting"}],packages:[],scripts:[],injections:[],apply:Ye};S();import pr from"node:path";import Za from"picocolors";P();S();P();import Wa from"node:fs/promises";import me from"node:path";import Ya from"degit";var vo=async(e,t)=>{t.text="Fetching assets from starter repo...",await Ya("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},wo=async(e,t)=>{let r=me.join(t,"src/i18n"),n=me.join(e,c.I18N_DIR);await Wa.cp(r,n,{recursive:!0});let o=me.join(t,"src/proxy.ts"),i=me.join(e,c.PROXY);await j(o,i);let s=me.join(t,"src/types/i18n.ts"),a=me.join(e,c.I18N_TYPES);await j(s,a);let p=me.join(t,"src/lib/config/app-locales.ts"),d=me.join(e,c.APP_LOCALES);await j(p,d)};S();P();import Ct from"node:path";var So=async e=>{let t=Ct.join(e,c.I18N_DIR),r=Ct.join(e,"package.json");if(m(t))return{isSetup:!0,reason:"src/i18n directory exists"};if(m(r)){let n=JSON.parse(await f(r));if(n.dependencies?.["next-intl"]||n.devDependencies?.["next-intl"])return{isSetup:!0,reason:"next-intl is installed"}}return{isSetup:!1,reason:""}},Co=async e=>{let t=Ct.join(e,c.ROOT_LAYOUT),r=Ct.join(e,"src/app/[locale]/layout.tsx");if(!m(t)&&!m(r))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx exists.")};S();P();import Ka from"node:fs/promises";import se from"node:path";var To=async e=>{let t=se.join(e,c.NEXT_CONFIG);if(m(t)){let r=await f(t);if(!r.includes("createNextIntlPlugin")){r=`import createNextIntlPlugin from 'next-intl/plugin';
|
|
720
|
+
${r}`;let n=/export default (.*?);/;n.test(r)?r=r.replace(n,`
|
|
721
721
|
const withNextIntl = createNextIntlPlugin();
|
|
722
|
-
export default withNextIntl($1);`):(
|
|
722
|
+
export default withNextIntl($1);`):(r+=`
|
|
723
723
|
const withNextIntl = createNextIntlPlugin();
|
|
724
|
-
`,
|
|
725
|
-
`),await
|
|
726
|
-
`,await
|
|
727
|
-
`,await
|
|
724
|
+
`,r+=`export default withNextIntl(nextConfig);
|
|
725
|
+
`),await g(t,r)}}},Eo=async e=>{let t=se.join(e,c.TYPES_INDEX);if(m(t)){let r=await f(t);r.includes("./i18n")||(r+=`export * from './i18n';
|
|
726
|
+
`,await g(t,r))}},bo=async e=>{let t=se.join(e,c.CONFIG_INDEX);if(m(t)){let r=await f(t);r.includes("./app-locales")||(r+=`export * from './app-locales';
|
|
727
|
+
`,await g(t,r))}},Ro=async e=>{let t=se.join(e,"src/providers/RootProvider.tsx");if(m(t)){let r=await f(t),n="'use client';",o=r.includes(n);if(o&&(r=r.replace(n,"").trim()),r.includes("next-intl")||(r=`import { type AbstractIntlMessages, NextIntlClientProvider } from 'next-intl';
|
|
728
728
|
import type { SupportedLocale } from '@/types/i18n';
|
|
729
|
-
`+
|
|
730
|
-
${
|
|
729
|
+
`+r),o&&(r=`${n}
|
|
730
|
+
${r}`),!r.includes("locale: SupportedLocale")){let i=` locale: SupportedLocale;
|
|
731
731
|
messages: AbstractIntlMessages;
|
|
732
|
-
timeZone: string;`,s=/(type\s+RootProviderProps\s*=\s*\{)([\s\S]*?)(\};?)/,a=/export const RootProvider = \(\{([\s\S]*?)\}: \{([\s\S]*?)\}\) => \{/;if(s.test(
|
|
732
|
+
timeZone: string;`,s=/(type\s+RootProviderProps\s*=\s*\{)([\s\S]*?)(\};?)/,a=/export const RootProvider = \(\{([\s\S]*?)\}: \{([\s\S]*?)\}\) => \{/;if(s.test(r))r=r.replace(s,(p,d,u,h)=>{let x=u.replace(/\s+$/,"");return`${d}${x}
|
|
733
733
|
${i}
|
|
734
|
-
${h}`}),
|
|
734
|
+
${h}`}),r=r.replace(/export const RootProvider = \(\{([\s\S]*?)\}:\s*RootProviderProps\)/,(p,d)=>{let u=d.trim().replace(/,$/,"");return`export const RootProvider = ({ ${u?`${u}, `:""}locale, messages, timeZone }: RootProviderProps)`});else{let p=r.match(a);if(p){let d=p[1].trim().replace(/,$/,""),u=p[2].trim().replace(/;$/,""),h=`
|
|
735
735
|
${d?`${d},
|
|
736
736
|
`:""}locale,
|
|
737
737
|
messages,
|
|
738
738
|
timeZone,`,x=`
|
|
739
|
-
${
|
|
739
|
+
${u?`${u};
|
|
740
740
|
`:""}locale: SupportedLocale;
|
|
741
741
|
messages: AbstractIntlMessages;
|
|
742
|
-
timeZone: string;`;
|
|
742
|
+
timeZone: string;`;r=r.replace(p[0],`export const RootProvider = ({${h}
|
|
743
743
|
}: {${x}
|
|
744
|
-
}) => {`)}}}if(!
|
|
744
|
+
}) => {`)}}}if(!r.includes("<NextIntlClientProvider")){let i=r.match(/return\s*(?:\(\s*)?([\s\S]*?)(?:\s*\))?;/);if(i){let s=i[1],a=`<NextIntlClientProvider locale={locale} messages={messages} timeZone={timeZone}>
|
|
745
745
|
{children}
|
|
746
|
-
</NextIntlClientProvider>`;if(s.includes("{children}")){let p=s.replace("{children}",a);
|
|
746
|
+
</NextIntlClientProvider>`;if(s.includes("{children}")){let p=s.replace("{children}",a);r=r.replace(i[0],`return (
|
|
747
747
|
${p}
|
|
748
|
-
);`)}else
|
|
748
|
+
);`)}else r=r.replace(i[0],`return (
|
|
749
749
|
<NextIntlClientProvider locale={locale} messages={messages} timeZone={timeZone}>
|
|
750
750
|
${s}
|
|
751
751
|
</NextIntlClientProvider>
|
|
752
|
-
);`)}}await
|
|
752
|
+
);`)}}await g(t,r)}},$o=async e=>{let t=se.join(e,c.ROOT_LAYOUT),r=se.join(e,c.ROOT_PAGE),n=se.join(e,"src/app/[locale]");if(await Ka.mkdir(n,{recursive:!0}),m(t)){let o=se.join(n,"layout.tsx"),i=await f(t);if(i.includes("next-intl")||(i=`import { routing } from '@/i18n/routing';
|
|
753
753
|
import { hasLocale } from 'next-intl';
|
|
754
754
|
import { notFound } from 'next/navigation';
|
|
755
755
|
import { getMessages, getTimeZone, setRequestLocale } from 'next-intl/server';
|
|
@@ -761,7 +761,7 @@ export function generateStaticParams() {
|
|
|
761
761
|
}`+i.slice(d)}}i=i.replace(/Readonly<\{\s*children:\s*React\.ReactNode;\s*}>/,`Readonly<{
|
|
762
762
|
children: React.ReactNode;
|
|
763
763
|
params: Promise<{ locale: string }>;
|
|
764
|
-
}>`);let s=/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,a=i.match(s);if(a){a[1]||(i=i.replace("export default function","export default async function")),i=i.replace(/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,"export default async function RootLayout({ children, params }:");let d=/export default async function RootLayout[\s\S]*?\)\s*\{/,
|
|
764
|
+
}>`);let s=/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,a=i.match(s);if(a){a[1]||(i=i.replace("export default function","export default async function")),i=i.replace(/export default (async )?function RootLayout\(\{\s*children,?\s*\}\s*:/,"export default async function RootLayout({ children, params }:");let d=/export default async function RootLayout[\s\S]*?\)\s*\{/,u=i.match(d);if(u&&u.index!==void 0){let h=u.index+u[0].length-1;i=i.slice(0,h+1)+`
|
|
765
765
|
const { locale } = await params;
|
|
766
766
|
|
|
767
767
|
if (!hasLocale(routing.locales, locale)) {
|
|
@@ -771,7 +771,7 @@ export function generateStaticParams() {
|
|
|
771
771
|
setRequestLocale(locale);
|
|
772
772
|
|
|
773
773
|
const [messages, timeZone] = await Promise.all([getMessages(), getTimeZone()]);
|
|
774
|
-
`+i.slice(h+1)}i=i.replace(/<RootProvider>/,"<RootProvider locale={locale} messages={messages} timeZone={timeZone}>"),i=i.replace(/<html lang="en"/,"<html lang={locale} dir={getLocaleDirection(locale)}")}await
|
|
774
|
+
`+i.slice(h+1)}i=i.replace(/<RootProvider>/,"<RootProvider locale={locale} messages={messages} timeZone={timeZone}>"),i=i.replace(/<html lang="en"/,"<html lang={locale} dir={getLocaleDirection(locale)}")}await g(o,i),await T(t)}if(m(r)){let o=se.join(n,"page.tsx"),i=await f(r);i.includes("next-intl")||(i=`import { SupportedLocale } from '@/types/i18n';
|
|
775
775
|
import { setRequestLocale } from 'next-intl/server';
|
|
776
776
|
${i}`),i=i.replace(/export default function Home\(\)/,`type Props = {
|
|
777
777
|
params: Promise<{ locale: string }>;
|
|
@@ -780,33 +780,33 @@ ${i}`),i=i.replace(/export default function Home\(\)/,`type Props = {
|
|
|
780
780
|
export default async function Home(props: Props)`);let s=i.indexOf("export default async function Home(props: Props) {");if(s!==-1){let a=`
|
|
781
781
|
const locale = (await props.params).locale as SupportedLocale;
|
|
782
782
|
setRequestLocale(locale);
|
|
783
|
-
`,p=i.indexOf("{",s);i=i.slice(0,p+1)+a+i.slice(p+1)}await
|
|
784
|
-
reactCompiler: true,`),await
|
|
785
|
-
${
|
|
786
|
-
${
|
|
787
|
-
${
|
|
788
|
-
preloadedState?: Partial<AppState>;`),
|
|
783
|
+
`,p=i.indexOf("{",s);i=i.slice(0,p+1)+a+i.slice(p+1)}await g(o,i),await T(r)}};var Ke=async e=>{let t=b("Setting up Internationalization (next-intl)..."),r=pr.join(e,".next-maker-temp-i18n");try{let{isSetup:n,reason:o}=await So(e);if(n){t.fail(`i18n is already set up (${o}).`);return}await Co(e),await vo(r,t),t.text="Copying i18n files...",await wo(e,r),t.text="Configuring project structure...",await To(e),await Eo(e),await bo(e),await Ro(e),t.text="Migrating to [locale] structure...",await $o(e),t.text="Installing dependencies...",await q(e,"next-intl");let i=pr.join(e,c.VITEST_CONFIG);if(m(i)){let a=JSON.parse(await f(pr.join(e,c.PACKAGE_JSON))),p={...a.dependencies,...a.devDependencies},d=!!(p["@reduxjs/toolkit"]&&p["react-redux"]);await ce(e,{redux:d,i18n:!0})}t.text="Formatting code...";let s=await _(e);await B(e,s,"lint:fix"),t.succeed(Za.green("Internationalization setup successfully!"))}catch(n){throw t.fail("Failed to setup Internationalization."),n}finally{await w(r)}};var Io={id:"i18n",name:"Internationalization",description:"next-intl with [locale] routing, RootProvider, and proxy.ts",detect:async e=>{let{detectProjectSetup:t}=await Promise.resolve().then(()=>(G(),De));return(await t(e)).hasI18n},files:[{path:"src/i18n",generated:!0,isDir:!0,containsUserContent:!0,removeHint:"holds your translation JSON files \u2014 copy any you want to keep, then delete by hand"},{path:"src/proxy.ts",generated:!0},{path:"src/app/[locale]",generated:!0,isDir:!0,containsUserContent:!0,removeHint:"holds every page you generated under the locale segment \u2014 move them to src/app/ before deleting"}],packages:[{name:"next-intl",kind:"dependency"}],scripts:[],injections:[{file:"next.config.ts",description:"createNextIntlPlugin wrap in next.config.ts",presence:/next-intl\/plugin/,removePattern:Yn},{file:"src/providers/RootProvider.tsx",description:"<NextIntlClientProvider> wrap",presence:/NextIntlClientProvider/,removePattern:$e("NextIntlClientProvider")}],apply:Ke};S();P();import tc from"node:path";S();import Qa from"node:path";import ec from"picocolors";P();var Ze=async e=>{let t=b("Enabling React Compiler...");try{let r=Qa.join(e,c.NEXT_CONFIG);if(!m(r))throw new Error(`${c.NEXT_CONFIG} not found.`);let n=await f(r);if(n.includes("reactCompiler:")){t.fail("React Compiler is already configured in next.config.ts.");return}let o=/(const\s+nextConfig\s*:\s*NextConfig\s*=\s*\{)/;if(!o.test(n))throw new Error("Could not locate `const nextConfig: NextConfig = {` in next.config.ts.");n=n.replace(o,`$1
|
|
784
|
+
reactCompiler: true,`),await g(r,n),t.text="Installing babel-plugin-react-compiler...",await mt(e,"babel-plugin-react-compiler"),t.succeed(ec.green("React Compiler enabled."))}catch(r){throw t.fail("Failed to enable React Compiler."),r}};var No={id:"react-compiler",name:"React Compiler",description:"reactCompiler: true in next.config.ts + babel-plugin-react-compiler",detect:async e=>{let t=tc.join(e,c.NEXT_CONFIG);return m(t)?/reactCompiler\s*:\s*true/.test(await f(t)):!1},files:[],packages:[{name:"babel-plugin-react-compiler",kind:"devDependency"}],scripts:[],injections:[{file:c.NEXT_CONFIG,description:"`reactCompiler: true` flag",presence:/reactCompiler\s*:\s*true/,removePattern:/\n\s*reactCompiler:\s*true,?/}],apply:Ze};S();import dr from"node:path";import nc from"picocolors";P();S();P();import ko from"node:fs/promises";import we from"node:path";import rc from"degit";var Ao=async(e,t)=>{t.text="Fetching assets from starter repo...",await rc("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(e)},Oo=async(e,t)=>{let r=we.join(t,"src/providers/StoreProvider.tsx"),n=we.join(e,c.STORE_PROVIDER);await j(r,n);let o=we.join(t,"src/store"),i=we.join(e,c.STORE);await ko.cp(o,i,{recursive:!0})},Fo=async(e,t)=>{let r=we.join(t,"src/features/counter"),n=we.join(e,c.COUNTER_FEATURE);await ko.cp(r,n,{recursive:!0});let o=we.join(n,"components/Counter.tsx");if(await m(o)){let i=await f(o);i=i.replace(/import \{ useTranslations \} from 'next-intl';\n?/,""),i=i.replace(/const t = useTranslations\('Count'\);\n?/,""),i=i.replace(/\{t\('currentCount', \{ count: value \}\)\}/g,"Current Count: {value}"),i=i.replace(/\{t\('increment'\)\}/g,"Increment"),i=i.replace(/\{t\('decrement'\)\}/g,"Decrement"),i=i.replace(/\{t\('reset'\)\}/g,"Reset"),await g(o,i)}};S();P();import lr from"node:path";var _o=async e=>{let t=lr.join(e,c.STORE),r=lr.join(e,"package.json");if(m(t))return{isSetup:!0,reason:"src/store directory exists"};if(m(r)){let n=JSON.parse(await f(r));if(n.dependencies?.["@reduxjs/toolkit"]||n.devDependencies?.["@reduxjs/toolkit"])return{isSetup:!0,reason:"@reduxjs/toolkit is installed"}}return{isSetup:!1,reason:""}},jo=async e=>{let t=lr.join(e,c.PROVIDERS_INDEX);if(!await Pt(e)||!m(t))throw new Error("Project structure mismatch. Ensure src/app/layout.tsx (or src/app/[locale]/layout.tsx) and src/providers/index.ts exist.")};S();P();import mr from"node:path";var Do=async e=>{},Lo=async e=>{let t=mr.join(e,"src/providers/RootProvider.tsx");if(!m(t))return;let r=await f(t),n="'use client';",o=r.includes(n);if(o&&(r=r.replace(n,"").trim()),r.includes("from '@/store'")||(r=`import type { AppState } from '@/store';
|
|
785
|
+
${r}`),r.includes("from './StoreProvider'")||(r=`${r.includes("from '@/store'"),""}import { StoreProvider } from './StoreProvider';
|
|
786
|
+
${r}`),o&&(r=`${n}
|
|
787
|
+
${r}`),r.includes("preloadedState")||(r=r.replace(/children:\s*React\.ReactNode;/,`children: React.ReactNode;
|
|
788
|
+
preloadedState?: Partial<AppState>;`),r=r.replace(/export const RootProvider = \(\{([\s\S]*?)\}:/,(i,s)=>`export const RootProvider = ({${s}, preloadedState }:`),r=r.replace(/,\s*,/g,",").replace(/\{\s*,/g,"{ ").replace(/,\s*\}/g," }")),!r.includes("<StoreProvider")){let i=r.match(/return\s*\(\s*([\s\S]*?)\s*\);/);if(i){let s=i[1];r=r.replace(i[0],`return (
|
|
789
789
|
<StoreProvider preloadedState={preloadedState}>
|
|
790
790
|
${s}
|
|
791
791
|
</StoreProvider>
|
|
792
|
-
);`)}}await
|
|
792
|
+
);`)}}await g(t,r)},Mo=async e=>{let t=[mr.join(e,c.ROOT_PAGE),mr.join(e,"src/app/[locale]/page.tsx")],r="";for(let o of t)if(m(o)){r=o;break}if(!r)return;let n=await f(r);if(n.includes("Counter")||(n=`import { Counter } from '@/features/counter';
|
|
793
793
|
${n}`),!n.includes("<Counter />")){let o=n.lastIndexOf("</div>"),i=n.lastIndexOf("</main>"),s=i!==-1?i:o;s!==-1&&(n=n.slice(0,s)+`
|
|
794
794
|
<div className="mt-8">
|
|
795
795
|
<h2 className="mb-4 text-2xl font-bold">Redux Counter</h2>
|
|
796
796
|
<Counter />
|
|
797
797
|
</div>
|
|
798
|
-
`+n.slice(s),await
|
|
798
|
+
`+n.slice(s),await g(r,n))}};var Qe=async e=>{let t=b("Setting up Redux Toolkit..."),r=dr.join(e,".next-maker-temp-redux");try{let{isSetup:n,reason:o}=await _o(e);if(n){t.fail(`Redux is already set up (${o}).`);return}await jo(e),await Ao(r,t),t.text="Copying Redux files...",await Oo(e,r),t.text="Creating Counter feature...",await Fo(e,r),t.text="Updating providers and pages...",await Do(e),await Lo(e),await Mo(e),t.text="Installing dependencies...",await q(e,"@reduxjs/toolkit"),await q(e,"react-redux"),await q(e,"redux-persist"),await q(e,"react-secure-storage");let i=dr.join(e,c.VITEST_CONFIG);if(m(i)){let a=JSON.parse(await f(dr.join(e,c.PACKAGE_JSON))),p={...a.dependencies,...a.devDependencies};await ce(e,{redux:!0,i18n:!!p["next-intl"]})}t.text="Formatting code...";let s=await _(e);await B(e,s,"lint:fix"),t.succeed(nc.green("Redux Toolkit setup successfully!"))}catch(n){throw t.fail("Failed to setup Redux Toolkit."),n}finally{await w(r)}};var Go={id:"redux",name:"Redux Toolkit",description:"Redux Toolkit + react-redux + redux-persist + StoreProvider",detect:async e=>{let{detectProjectSetup:t}=await Promise.resolve().then(()=>(G(),De));return(await t(e)).hasRedux},files:[{path:"src/store",generated:!0,isDir:!0,containsUserContent:!0,removeHint:"holds the rootReducer and any slices you registered \u2014 review before deleting"},{path:"src/providers/StoreProvider.tsx",generated:!0}],packages:[{name:"@reduxjs/toolkit",kind:"dependency"},{name:"react-redux",kind:"dependency"},{name:"redux-persist",kind:"dependency"}],scripts:[],injections:[{file:"src/providers/RootProvider.tsx",description:"<StoreProvider> wrap in RootProvider",presence:/<StoreProvider/,removePattern:$e("StoreProvider")}],apply:Qe};S();P();import cc from"node:path";S();import sc from"node:path";import ac from"picocolors";P();var Uo=[{key:"X-DNS-Prefetch-Control",value:"on"},{key:"Strict-Transport-Security",value:"max-age=63072000; includeSubDomains; preload"},{key:"X-XSS-Protection",value:"1; mode=block"},{key:"X-Frame-Options",value:"SAMEORIGIN"},{key:"X-Content-Type-Options",value:"nosniff"},{key:"Referrer-Policy",value:"origin-when-cross-origin"}],Ho=/(const\s+nextConfig\s*:\s*NextConfig\s*=\s*\{)/,oc=/^\s+headers\s*:/m,ic=e=>`
|
|
799
799
|
headers: async () => {
|
|
800
800
|
return [
|
|
801
801
|
{
|
|
802
802
|
source: '/:path*',
|
|
803
803
|
headers: [
|
|
804
|
-
${e.map(({key:
|
|
804
|
+
${e.map(({key:r,value:n})=>` { key: '${r}', value: '${n}' },`).join(`
|
|
805
805
|
`)}
|
|
806
806
|
],
|
|
807
807
|
},
|
|
808
808
|
];
|
|
809
|
-
},`,
|
|
809
|
+
},`,Ie=e=>oc.test(e),ur=(e,t=Uo)=>{if(Ie(e))return e;if(!Ho.test(e))throw new Error("Could not locate `const nextConfig: NextConfig = {` in next.config.ts.");return e.replace(Ho,`$1${ic(t)}`)};var et=async e=>{let t=b("Adding security headers to next.config.ts...");try{let r=sc.join(e,c.NEXT_CONFIG);if(!m(r))throw new Error(`${c.NEXT_CONFIG} not found.`);let n=await f(r);if(Ie(n)){t.succeed("Security headers already configured.");return}let o=ur(n);await g(r,o),t.succeed(ac.green("Security headers added."))}catch(r){throw t.fail("Failed to add security headers."),r}};var zo={id:"security-headers",name:"Security Headers",description:"Hardened HTTP headers in next.config.ts",detect:async e=>{let t=cc.join(e,c.NEXT_CONFIG);return m(t)?Ie(await f(t)):!1},files:[],packages:[],scripts:[],injections:[{file:c.NEXT_CONFIG,description:"headers() function in next.config.ts",presence:/^\s+headers\s*:/m,removePattern:/\s+headers:\s*async\s*\(\)\s*=>\s*\{[\s\S]*?\n\s{0,2}\},/m}],apply:et};S();P();import uc from"node:path";S();import pc from"node:fs/promises";import de from"node:path";import lc from"degit";import mc from"picocolors";P();var dc=["vitest","jsdom","@vitejs/plugin-react","@testing-library/dom","@testing-library/jest-dom","@testing-library/react","@testing-library/user-event"],tt=async e=>{let t=b("Setting up testing (Vitest + RTL)..."),r=de.join(e,".next-maker-temp-tests");try{let n=de.join(e,c.VITEST_CONFIG);if(m(n)){t.fail("Testing is already set up (vitest.config.ts exists).");return}t.text="Fetching assets from starter repo...",await lc("teispace/nextjs-starter",{cache:!1,force:!0,verbose:!1}).clone(r),await j(de.join(r,c.VITEST_CONFIG),de.join(e,c.VITEST_CONFIG));let i=de.join(e,c.TEST_DIR);await pc.mkdir(i,{recursive:!0}),await j(de.join(r,c.TEST_DIR,"setup.ts"),de.join(i,"setup.ts"));let s=de.join(e,c.PACKAGE_JSON),a=JSON.parse(await f(s)),p={...a.dependencies,...a.devDependencies},d=!!(p["@reduxjs/toolkit"]&&p["react-redux"]),u=!!p["next-intl"];await ce(e,{redux:d,i18n:u}),await F(s,x=>(x.scripts=x.scripts??{},x.scripts.test=x.scripts.test??"vitest run",x.scripts["test:watch"]=x.scripts["test:watch"]??"vitest",x.scripts["test:coverage"]=x.scripts["test:coverage"]??"vitest run --coverage",typeof x.scripts.validate=="string"&&!/\byarn\s+test(?![:\w])/.test(x.scripts.validate)&&(x.scripts.validate=x.scripts.validate.replace(/(\byarn\s+check:deprecated\s*)(&&)/,"$1&& yarn test $2")),x)),t.text="Installing testing devDependencies...";let h=await _(e);await xe(e,h,dc),t.text="Formatting code...",await B(e,h,"lint:fix"),t.succeed(mc.green("Testing setup complete."))}catch(n){throw t.fail("Failed to set up testing."),n}finally{await w(r)}};var Jo={id:"tests",name:"Tests",description:"Vitest + React Testing Library + jsdom",detect:async e=>m(uc.join(e,c.VITEST_CONFIG)),files:[{path:c.VITEST_CONFIG,generated:!0},{path:"test",generated:!0,isDir:!0,containsUserContent:!0,removeHint:"holds setup.ts / test-utils.tsx and any helpers you added \u2014 review before deleting"}],packages:[{name:"vitest",kind:"devDependency"},{name:"jsdom",kind:"devDependency"},{name:"@vitejs/plugin-react",kind:"devDependency"},{name:"@testing-library/dom",kind:"devDependency"},{name:"@testing-library/jest-dom",kind:"devDependency"},{name:"@testing-library/react",kind:"devDependency"},{name:"@testing-library/user-event",kind:"devDependency"}],scripts:[{name:"test",expectedValue:"vitest run"},{name:"test:watch",expectedValue:"vitest"}],injections:[],apply:tt};P();import xc from"node:path";S();import Vo from"node:path";import hc from"picocolors";P();var fc={npm:"npm run",yarn:"yarn",pnpm:"pnpm",bun:"bun run"},gc=e=>{let t=fc[e];return["ci:check","type-check","check:deprecated","test","build"].map(r=>`${t} ${r}`).join(" && ")},fr=(e,t)=>{let r={...e.scripts??{}},n={...e.devDependencies??{}};return r["env:sync"]||(r["env:sync"]="tsx scripts/sync-env.ts"),r["check:deprecated"]||(r["check:deprecated"]="tsx scripts/check-deprecated.ts"),r["type-check"]||(r["type-check"]="tsc --noEmit"),r.validate||(r.validate=gc(t)),!n.tsx&&!e.dependencies?.hasOwnProperty("tsx")&&(n.tsx="*"),{...e,scripts:r,devDependencies:n}};var gr=`import * as fs from 'node:fs';
|
|
810
810
|
import * as path from 'node:path';
|
|
811
811
|
|
|
812
812
|
const checkOnly = process.argv.includes('--check');
|
|
@@ -880,7 +880,7 @@ if (checkOnly) {
|
|
|
880
880
|
|
|
881
881
|
fs.writeFileSync(examplePath, newExampleContent);
|
|
882
882
|
console.log('\u2705 Synchronized .env.example with .env');
|
|
883
|
-
`,
|
|
883
|
+
`,hr=`/**
|
|
884
884
|
* Walks every identifier in the project and flags any whose resolved TypeScript
|
|
885
885
|
* symbol carries a \`@deprecated\` JSDoc tag. Catches deprecated API usage that
|
|
886
886
|
* \`tsc --noEmit\` does not surface (deprecations are "suggestion"-level, not
|
|
@@ -944,114 +944,121 @@ if (hits === 0) {
|
|
|
944
944
|
|
|
945
945
|
console.log(\`\\n\${hits} deprecated symbol use(s) found.\`);
|
|
946
946
|
process.exit(1);
|
|
947
|
-
`;var
|
|
948
|
-
`)},
|
|
947
|
+
`;var yc=[{relative:"scripts/sync-env.ts",content:gr},{relative:"scripts/check-deprecated.ts",content:hr}],rt=async e=>{let t=b("Adding validation scripts...");try{let r=!1;for(let{relative:i,content:s}of yc){let a=Vo.join(e,i);m(a)||(await g(a,s),r=!0)}let n=await _(e),o=!1;await F(Vo.join(e,c.PACKAGE_JSON),i=>{let s=i.devDependencies?.tsx,a=fr(i,n);return o=!s&&!!a.devDependencies?.tsx,a}),o&&(t.text="Installing tsx...",await xe(e,n,["tsx"])),t.succeed(hc.green(r?"Validation scripts added (env:sync, check:deprecated, validate).":"Validation scripts already present \u2014 refreshed package.json."))}catch(r){throw t.fail("Failed to add validation scripts."),r}};var Bo=["scripts/sync-env.ts","scripts/check-deprecated.ts"],qo={id:"validate-scripts",name:"Validation Scripts",description:"sync-env, check-deprecated, and the validate chain",detect:async e=>Bo.every(t=>m(xc.join(e,t))),files:Bo.map(e=>({path:e,generated:!0})),packages:[{name:"tsx",kind:"devDependency"}],scripts:[{name:"env:sync",expectedValue:"tsx scripts/sync-env.ts"},{name:"check:deprecated",expectedValue:"tsx scripts/check-deprecated.ts"},{name:"type-check",expectedValue:"tsc --noEmit"},{name:"validate"}],injections:[],apply:rt};S();P();import Ne from"node:path";var Xo=async e=>{let t=Ne.join(e,c.PACKAGE_JSON);return m(t)?JSON.parse(await f(t)):null},Pc=async(e,t)=>{let r=Ne.join(e,c.PACKAGE_JSON);await g(r,`${JSON.stringify(t,null,2)}
|
|
948
|
+
`)},Wo=(e,t)=>(t==="dependency"?e.dependencies:e.devDependencies)??{},nt=async(e,t)=>{let r=await e.detect(t),n=[];if(!r)return{manifest:e,installed:!1,drift:[]};for(let i of e.files)i.required!==!1&&(m(Ne.join(t,i.path))||n.push({kind:"missingFile",file:i.path}));let o=await Xo(t);if(o){for(let s of e.packages)Wo(o,s.kind)[s.name]||n.push({kind:"missingPackage",name:s.name,depKind:s.kind});let i=o.scripts??{};for(let s of e.scripts){let a=i[s.name];a?s.expectedValue&&a!==s.expectedValue&&n.push({kind:"mismatchedScript",name:s.name,expected:s.expectedValue,actual:a}):n.push({kind:"missingScript",name:s.name})}}for(let i of e.injections){let s=Ne.join(t,i.file);if(!m(s)){n.push({kind:"missingInjection",file:i.file,description:i.description});continue}let a=await f(s);i.presence.test(a)||n.push({kind:"missingInjection",file:i.file,description:i.description})}return{manifest:e,installed:r,drift:n}},Tt=async(e,t,r={})=>{let n=r.dryRun??!1,o={filesRemoved:[],packagesUninstalled:[],scriptsRemoved:[],blocksStripped:[],manualCleanup:[]};for(let a of e.injections){let p=Ne.join(t,a.file);if(!m(p))continue;if(!a.removePattern){o.manualCleanup.push({file:a.file,description:a.description});continue}let d=await f(p);if(!a.presence.test(d))continue;let u;if(typeof a.removePattern=="function"){let h=a.removePattern(d);if(h===null){o.manualCleanup.push({file:a.file,description:a.description});continue}u=h}else u=d.replace(a.removePattern,"");u!==d?(n||await g(p,u),o.blocksStripped.push({file:a.file,description:a.description})):o.manualCleanup.push({file:a.file,description:a.description})}let{rm:i}=await import("node:fs/promises");for(let a of e.files){if(!a.generated)continue;let p=Ne.join(t,a.path);if(m(p)){if(a.containsUserContent){let d=a.removeHint?`${a.path} \u2014 ${a.removeHint}`:`${a.path} (may contain user-authored files; review before deleting)`;o.manualCleanup.push({file:a.path,description:d});continue}n||await i(p,{recursive:!0,force:!0}),o.filesRemoved.push(a.path)}}let s=await Xo(t);if(s){let a=!1;if(s.scripts)for(let p of e.scripts)s.scripts[p.name]&&(n||delete s.scripts[p.name],o.scriptsRemoved.push(p.name),a=!0);for(let p of e.packages)Wo(s,p.kind)[p.name]&&o.packagesUninstalled.push(p.name);a&&!n&&await Pc(t,s)}if(!n&&o.packagesUninstalled.length>0){let a=await _(t);await At(t,a,o.packagesUninstalled)}return o};var Se=[zo,qo,eo,No,Zn,Jo,mo,Po,Go,Io],Yo=e=>Se.find(t=>t.id===e);var vc=e=>{switch(e.kind){case"missingFile":return`missing file: ${e.file}`;case"missingPackage":return`missing ${e.depKind==="dependency"?"dep":"devDep"}: ${e.name}`;case"missingScript":return`missing script: ${e.name}`;case"mismatchedScript":return`script "${e.name}" expected ${L.dim(e.expected)} but got ${L.dim(e.actual)}`;case"missingInjection":return`missing block in ${e.file}: ${e.description}`}},wc=e=>{let t=e.filter(n=>n.installed),r=t.filter(n=>n.drift.length>0);return{installedCount:t.length,driftedCount:r.length,cleanCount:t.length-r.length,driftedResults:r}},Ko=e=>{e.command("doctor").description("Diagnose drift between the project and known feature manifests").option("--fix","Re-apply manifests that report drift (idempotent)").option("--feature <id>","Only check this manifest id (e.g. redux, security-headers)").option("--json","Print machine-readable JSON instead of the human report").action(async t=>{try{let r=process.cwd(),n=t.feature?Se.filter(s=>s.id===t.feature):Se;if(t.feature&&n.length===0)throw new Error(`Unknown feature "${t.feature}". Valid: ${Se.map(s=>s.id).join(", ")}.`);let o=[];for(let s of n)o.push(await nt(s,r));t.json&&(l(JSON.stringify(o.map(s=>({id:s.manifest.id,name:s.manifest.name,installed:s.installed,drift:s.drift})),null,2)),process.exit(o.some(s=>s.drift.length>0)?1:0)),l(L.cyan(`
|
|
949
949
|
\u{1FA7A} Project Doctor
|
|
950
|
-
`));for(let s of o){let{manifest:a,installed:p,drift:d}=s;if(!p){l(` ${
|
|
950
|
+
`));for(let s of o){let{manifest:a,installed:p,drift:d}=s;if(!p){l(` ${L.dim("\u2014")} ${L.dim(a.name)} ${L.dim("(not installed)")}`);continue}if(d.length===0){l(` ${L.green("\u2713")} ${a.name}`);continue}l(` ${L.yellow("!")} ${L.bold(a.name)} ${L.dim(`(${d.length} issue${d.length===1?"":"s"})`)}`);for(let u of d)l(` ${L.yellow("\u2022")} ${vc(u)}`)}let i=wc(o);l(""),l(L.dim(`${i.cleanCount} clean, ${i.driftedCount} drifted, ${o.length-i.installedCount} not installed`)),i.driftedCount===0&&(l(L.green(`
|
|
951
951
|
\u2713 No drift detected.
|
|
952
|
-
`)),process.exit(0)),
|
|
952
|
+
`)),process.exit(0)),t.fix||(l(L.dim(`
|
|
953
953
|
Run with --fix to re-apply drifted features.
|
|
954
|
-
`)),process.exit(1)),l(
|
|
954
|
+
`)),process.exit(1)),l(L.cyan(`
|
|
955
955
|
\u{1F527} Applying fixes...
|
|
956
|
-
`));for(let s of i.driftedResults){if(!s.manifest.apply){l(
|
|
956
|
+
`));for(let s of i.driftedResults){if(!s.manifest.apply){l(L.yellow(` \u26A0\uFE0F ${s.manifest.name} has no apply() \u2014 skipping.`));continue}try{await s.manifest.apply(r)}catch(a){v(`Failed to fix ${s.manifest.name}: ${a}`)}}l(L.green(`
|
|
957
957
|
\u2713 Doctor finished.
|
|
958
|
-
`))}catch(
|
|
959
|
-
.describe('${a}')`}return` ${
|
|
960
|
-
${
|
|
961
|
-
`;return e.replace(
|
|
958
|
+
`))}catch(r){v(`${r instanceof Error?r.message:r}`),process.exit(1)}})};import ke from"picocolors";S();P();import yr from"node:path";var Sc=/^[A-Z][A-Z0-9_]*$/,Qo=e=>{if(!Sc.test(e))throw new Error(`Invalid env var name "${e}". Use UPPER_SNAKE_CASE (e.g. SENTRY_DSN, NEXT_PUBLIC_API_URL).`)},ue=(e,t)=>t?e.startsWith("NEXT_PUBLIC_")?e:`NEXT_PUBLIC_${e}`:e,Cc=e=>{if(e.default===void 0)return"";switch(e.type){case"number":return`.default(${Number(e.default)})`;case"boolean":return`.default(${e.default==="true"})`;default:return`.default('${e.default.replace(/'/g,"\\'")}')`}},Tc=e=>{switch(e.type){case"url":return"z.url()";case"number":return"z.coerce.number()";case"boolean":return"z.coerce.boolean()";case"enum":{let t=e.enumValues??[];if(t.length===0)throw new Error(`Enum env var "${e.name}" requires --enum values.`);return`z.enum([${t.map(n=>`'${n.replace(/'/g,"\\'")}'`).join(", ")}])`}default:return"z.string()"}},ei=e=>{let t=ue(e.name,e.public),n=Tc(e),o=e.default!==void 0,i=!e.required&&!o;o&&(n+=Cc(e)),i&&e.type!=="enum"&&(n+=".optional()");let s;if(e.type==="enum"?s=n:s=`z.preprocess(emptyStringToUndefined, ${n})`,e.description){let a=e.description.replace(/'/g,"\\'");s+=`
|
|
959
|
+
.describe('${a}')`}return` ${t}: ${s},`},Zo=/(export const envSchema\s*=\s*z\.object\(\{)([\s\S]*?)(\}\);?)/,ti=(e,t)=>{let r=ue(t.name,t.public);if(new RegExp(`\\b${r}\\s*:`).test(e))return e;let o=e.match(Zo);if(!o)throw new Error("Could not locate `export const envSchema = z.object({ \u2026 })` in schema.ts.");let[,i,s,a]=o,p=s.replace(/\s+$/,""),d=p.length===0||/,\s*$/.test(p)?p:`${p},`,u=ei(t),h=`${d}
|
|
960
|
+
${u}
|
|
961
|
+
`;return e.replace(Zo,`${i}${h}${a}`)},Ec="# -public",bc=e=>{let t=ue(e.name,e.public),r=e.default??"",n=e.public?` ${Ec}`:"";return`${t}=${r}${n}`},ri=(e,t)=>{let r=ue(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
|
|
962
962
|
`)?"":`
|
|
963
963
|
`,i=e===""?"":`
|
|
964
|
-
`,s=
|
|
965
|
-
`:"";return`${e}${o}${i}${s}${
|
|
966
|
-
`},
|
|
964
|
+
`,s=t.description?`# ${t.description}
|
|
965
|
+
`:"";return`${e}${o}${i}${s}${bc(t)}
|
|
966
|
+
`},ni=(e,t)=>{let r=ue(t.name,t.public);if(new RegExp(`^${r}=`,"m").test(e))return e;let o=e===""||e.endsWith(`
|
|
967
967
|
`)?"":`
|
|
968
|
-
`,i=
|
|
969
|
-
`},
|
|
968
|
+
`,i=t.default??"";return`${e}${o}${r}=${i}
|
|
969
|
+
`},xr=async(e,t)=>{Qo(t.name);let r=yr.join(e,"src/lib/env/schema.ts");if(!m(r))throw new Error("src/lib/env/schema.ts not found \u2014 run `next-maker init` first.");let n=await f(r),o=ti(n,t),i=o!==n;i&&await g(r,o);let s=yr.join(e,c.ENV_EXAMPLE),a=!1;if(m(s)){let u=await f(s),h=ri(u,t);a=h!==u,a&&await g(s,h)}let p=yr.join(e,".env"),d=!1;if(m(p)){let u=await f(p),h=ni(u,t);d=h!==u,d&&await g(p,h)}return{schemaUpdated:i,envExampleUpdated:a,envUpdated:d}};var oi=new Set(["string","url","number","boolean","enum"]),Rc=e=>{let t=(e??"string").toLowerCase();if(!oi.has(t))throw new Error(`Invalid --type "${e}". Valid: ${Array.from(oi).join(", ")}.`);return t},$c=e=>{if(!e)return;let t=e.split(",").map(r=>r.trim()).filter(Boolean);return t.length===0?void 0:t},ii=e=>{e.command("env <NAME>").description("Declare a new environment variable across schema, .env.example, and .env").option("--type <type>","Zod type (string|url|number|boolean|enum)","string").option("--required","Make the variable required (no .optional() / .default())").option("--default <value>","Set a default value (mutually exclusive with --required)").option("--public","Mark as public (auto-prefix NEXT_PUBLIC_ and tag .env.example)").option("--describe <text>","Description (rendered as .describe() and .env.example comment)").option("--enum <list>",'Comma-separated values when --type=enum (e.g. "dev,prod")').action(async(t,r)=>{try{let n=process.cwd();if(l(ke.cyan(`
|
|
970
970
|
\u{1F510} Env Var Generator
|
|
971
|
-
`)),
|
|
971
|
+
`)),r.required&&r.default!==void 0)throw new Error("--required and --default are mutually exclusive.");let o=Rc(r.type),i=$c(r.enum);if(o==="enum"&&(!i||i.length===0))throw new Error("--type=enum requires at least one value via --enum a,b,c.");let s={name:t,type:o,required:!!r.required,default:r.default,description:r.describe,enumValues:i,public:!!r.public};y.start("Updating schema, .env.example, and .env...");let a=await xr(n,s);y.succeed("Env var written");let p=ue(s.name,s.public);l(ke.green(`
|
|
972
972
|
\u2728 ${p} declared.
|
|
973
|
-
`)),l(
|
|
974
|
-
|
|
975
|
-
${e
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
${r}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
973
|
+
`)),l(ke.dim("Touched:")),l(ke.dim(` ${a.schemaUpdated?"\u270F\uFE0F ":"\u23ED "} src/lib/env/schema.ts`)),l(ke.dim(` ${a.envExampleUpdated?"\u270F\uFE0F ":"\u23ED "} .env.example`)),l(ke.dim(` ${a.envUpdated?"\u270F\uFE0F ":"\u23ED "} .env`)),l("")}catch(n){y.fail("Env var declaration failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Rt from"node:path";import Te from"picocolors";import Ic from"enquirer";var{prompt:Nc}=Ic,si=async(e={})=>e.source?{source:e.source}:{source:(await Nc({type:"input",name:"source",message:"Path to source image (PNG/JPG/JPEG/SVG/WebP/AVIF):",validate:r=>r?!0:"Source path is required"})).source};import{access as kc,readFile as Ac,stat as Oc}from"node:fs/promises";import Ce from"node:path";var ai=async e=>{try{return await kc(e),!0}catch{return!1}},Fc=async e=>{try{return(await Oc(e)).isDirectory()}catch{return!1}},Et=async e=>{let t=[Ce.join(e,"src","app"),Ce.join(e,"app")];for(let r of t)if(await Fc(r))return r;return null},_c=["next-pwa","@ducanh2912/next-pwa","@serwist/next","serwist"],Pr=async e=>{let t={isPwa:!1},r=[Ce.join(e,"public","manifest.json"),Ce.join(e,"public","manifest.webmanifest"),Ce.join(e,"public","site.webmanifest")];for(let o of r)if(await ai(o)){t.publicManifestPath=o,t.isPwa=!0;break}let n=await Et(e);if(n)for(let o of["ts","tsx","js"]){let i=Ce.join(n,`manifest.${o}`);if(await ai(i)){t.appManifestPath=i,t.isPwa=!0;break}}try{let o=JSON.parse(await Ac(Ce.join(e,"package.json"),"utf-8")),i={...o.dependencies,...o.devDependencies};for(let s of _c)if(i[s]){t.framework=s,t.isPwa=!0;break}}catch{}return t};import{mkdir as Gc,readFile as yi,stat as Hc,writeFile as Uc}from"node:fs/promises";import te from"node:path";import zc from"sharp";import Dc from"png-to-ico";import ot from"sharp";var ci=e=>e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<"),vr=(e,t,r)=>{switch(e){case"square":return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" fill="white"/></svg>`;case"circle":{let n=t/2;return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><circle cx="${n}" cy="${n}" r="${n}" fill="white"/></svg>`}case"rounded":{let n=Math.round(t*r/100);return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><rect width="${t}" height="${t}" rx="${n}" ry="${n}" fill="white"/></svg>`}case"squircle":return jc(t)}},jc=e=>{let t=e,r=t*.225,n=[`M 0 ${r}`,`C 0 0 0 0 ${r} 0`,`L ${t-r} 0`,`C ${t} 0 ${t} 0 ${t} ${r}`,`L ${t} ${t-r}`,`C ${t} ${t} ${t} ${t} ${t-r} ${t}`,`L ${r} ${t}`,`C 0 ${t} 0 ${t} 0 ${t-r}`,"Z"].join(" ");return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}"><path d="${ci(n)}" fill="white"/></svg>`},pi=(e,t)=>`<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${e}"><rect width="${e}" height="${e}" fill="${ci(t)}"/></svg>`;var Ae=async e=>{let{size:t,paddingPercent:r,bg:n,fit:o,shape:i,radiusPercent:s,quality:a,forceSquare:p,sourceBuffer:d}=e,u=Math.max(1,Math.round(t*(1-r*2/100))),h=o==="cover"?"cover":"contain",x=await ot(d,{density:384}).resize(u,u,{fit:h,background:{r:0,g:0,b:0,alpha:0}}).png().toBuffer(),k=Math.round((t-u)/2),z=n==="transparent"?{r:0,g:0,b:0,alpha:0}:await wr(n),$=await ot({create:{width:t,height:t,channels:4,background:z}}).composite([{input:x,left:k,top:k}]).png().toBuffer();if(!p&&(i!=="square"||o==="clip")){let he=i==="square"?"rounded":i,qi=Buffer.from(vr(he,t,s));$=await ot($).composite([{input:qi,blend:"dest-in"}]).png({compressionLevel:li(a)}).toBuffer()}else $=await ot($).png({compressionLevel:li(a)}).toBuffer();return $},wr=async e=>{let t=await ot(Buffer.from(pi(1,e))).raw().toBuffer({resolveWithObject:!0}),[r,n,o,i=255]=t.data;return{r,g:n,b:o,alpha:i/255}},li=e=>{let t=Math.round((100-e)/100*9);return Math.max(0,Math.min(9,t))},mi=async e=>{if(e.length===0)throw new Error("No frames provided to encodeIco");return Dc(e)};import{readFile as Lc,writeFile as Hx}from"node:fs/promises";var di=e=>e.map(({src:t,size:r})=>({src:t,sizes:`${r}x${r}`,type:"image/png",purpose:"any maskable"})),ui=async(e,t)=>{let r=await Lc(e,"utf-8"),n=JSON.parse(r),o=Array.isArray(n.icons)?n.icons:[],i=new Map;for(let s of[...o,...t])s&&typeof s.src=="string"&&i.set(s.src,s);return n.icons=[...i.values()],`${JSON.stringify(n,null,2)}
|
|
974
|
+
`};var fi=e=>`icons: [
|
|
975
|
+
${e.map(r=>` { src: '${r.src}', sizes: '${r.sizes}', type: '${r.type}'${r.purpose?`, purpose: '${r.purpose}'`:""} }`).join(`,
|
|
976
|
+
`)},
|
|
977
|
+
],`,gi=(e,t,r)=>`${JSON.stringify({name:e,short_name:e,start_url:"/",display:"standalone",background_color:"#ffffff",theme_color:t,icons:r},null,2)}
|
|
978
|
+
`;import{stat as Mc}from"node:fs/promises";import Sr from"node:path";var hi=[".png",".jpg",".jpeg",".webp",".svg",".avif"],bt=async e=>{if(!e)throw new Error("Source image path is required (use --path).");let t=Sr.isAbsolute(e)?e:Sr.resolve(process.cwd(),e),r;try{r=await Mc(t)}catch{throw new Error(`Source image not found: ${t}`)}if(!r.isFile())throw new Error(`Source is not a file: ${t}`);let n=Sr.extname(t).toLowerCase();if(!hi.includes(n))throw new Error(`Unsupported source format '${n}'. Use one of: ${hi.join(", ")}`);return{absolutePath:t,ext:n,bytes:r.size,isVector:n===".svg"}};var Cr=(e,t)=>{if(!e)return t;let r=e.split(",").map(n=>Number.parseInt(n.trim(),10)).filter(n=>Number.isFinite(n)&&n>0&&n<=1024);if(r.length===0)throw new Error(`Invalid --sizes value: '${e}'. Provide comma-separated positive integers.`);return r};var Jc=async e=>{try{return await Hc(e),!0}catch{return!1}},Vc=async(e,t,r)=>{let n=[];for(let o of e){if(await Jc(o.outPath)&&!t&&!o.alwaysWrite){n.push({path:o.outPath,bytes:o.bytes.length,skipped:!0});continue}r||(await Gc(te.dirname(o.outPath),{recursive:!0}),await Uc(o.outPath,o.bytes)),n.push({path:o.outPath,bytes:o.bytes.length})}return n},Tr=async(e,t)=>{let r=await bt(t.source),n=await yi(r.absolutePath),o=t.ogSource?await yi((await bt(t.ogSource)).absolutePath):n,i=[],s=[];for(let u of t.icoSizes)s.push(await Ae({sourceBuffer:n,size:u,shape:"square",radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality,forceSquare:!0}));let a=await mi(s);if(i.push({outPath:te.join(t.outDir,"favicon.ico"),bytes:a}),t.emitIcon){let u=await Ae({sourceBuffer:n,size:512,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality});i.push({outPath:te.join(t.outDir,"icon.png"),bytes:u})}if(t.emitApple){let u=t.bg==="transparent"?"#ffffff":t.bg,h=await Ae({sourceBuffer:n,size:180,shape:t.shape,radiusPercent:t.radius,bg:u,paddingPercent:t.padding,fit:t.fit,quality:t.quality});i.push({outPath:te.join(t.outDir,"apple-icon.png"),bytes:h})}if(t.emitOg){let u=await xi(o,t,!1);i.push({outPath:te.join(t.outDir,"opengraph-image.png"),bytes:u})}if(t.emitTwitter){let u=await xi(o,t,!0);i.push({outPath:te.join(t.outDir,"twitter-image.png"),bytes:u})}let p;if(t.pwa||t.pwaInit){let u=await Pr(e);if(t.pwa&&!u.isPwa)throw new Error("No PWA setup detected. Use --pwa-init to bootstrap a manifest, or set up next-pwa/serwist first.");let h=te.join(e,"public"),x=[192,512],k=[];for(let $ of x){let J=await Ae({sourceBuffer:n,size:$,shape:t.shape,radiusPercent:t.radius,bg:t.bg,paddingPercent:t.padding,fit:t.fit,quality:t.quality}),he=`icon-${$}.png`;i.push({outPath:te.join(h,he),bytes:J}),k.push({src:`/${he}`,size:$})}let z=di(k);if(u.publicManifestPath){let $=await ui(u.publicManifestPath,z);i.push({outPath:u.publicManifestPath,bytes:Buffer.from($,"utf-8"),alwaysWrite:!0})}else if(u.appManifestPath)p=fi(z);else if(t.pwaInit){let $=te.join(h,"manifest.webmanifest"),J=gi(te.basename(e)||"App","#000000",z);i.push({outPath:$,bytes:Buffer.from(J,"utf-8")})}}return{outputs:await Vc(i,t.force,t.dryRun),pwaSnippet:p}},xi=async(e,t,r)=>{let o=r?600:630,i=Math.round(Math.min(1200,o)*(1-t.padding*2/100)),s=await Ae({sourceBuffer:e,size:i,shape:t.shape,radiusPercent:t.radius,bg:"transparent",paddingPercent:0,fit:t.fit,quality:t.quality}),a=t.bg==="transparent"?"#ffffff":t.bg,p=await wr(a),d=Math.round((1200-i)/2),u=Math.round((o-i)/2);return zc({create:{width:1200,height:o,channels:4,background:p}}).composite([{input:s,left:d,top:u}]).png().toBuffer()};var Pi=new Set(["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]);var Bc=["square","rounded","circle","squircle"],qc=["contain","cover","clip"],vi=(e,t,r,n)=>{if(!e)return r;if(!t.includes(e))throw new Error(`Invalid value for --${n}: '${e}'. Allowed: ${t.join(", ")}`);return e},Er=(e,t,r,n,o)=>{if(e===void 0)return t;let i=Number(e);if(!Number.isFinite(i)||i<n||i>o)throw new Error(`Invalid value for --${r}: '${e}'. Must be a number between ${n}\u2013${o}.`);return i},Si=e=>{e.command("favicon").description("Generate favicon.ico (and optionally icons, OG image, PWA manifest icons)").option("--path <file>","Path to source image (PNG, JPG, JPEG, WebP, SVG, AVIF)").option("--out <dir>","Output dir (default: src/app or app)").option("--force","Overwrite existing files without prompt",!1).option("--dry-run","Show what would be written without writing",!1).option("--icon","Also emit icon.png (512\xD7512)",!1).option("--apple","Also emit apple-icon.png (180\xD7180)",!1).option("--og","Also emit opengraph-image.png (1200\xD7630)",!1).option("--og-source <file>","Use a separate image for the OG/Twitter card").option("--twitter","Also emit twitter-image.png (1200\xD7600)",!1).option("--all","Shorthand for --icon --apple --og",!1).option("--pwa","Detect PWA setup and emit manifest icons (192/512); errors if not detected",!1).option("--pwa-init","Bootstrap public/manifest.webmanifest with icons",!1).option("--shape <shape>","square | rounded | circle | squircle","square").option("--radius <percent>","Corner radius % when shape=rounded (0-50)","20").option("--bg <color>",'Background color (hex, css name, or "transparent")',"transparent").option("--padding <percent>","Padding around source content (0-30)","0").option("--fit <fit>","How source fits target: contain | cover | clip","contain").option("--sizes <list>","Comma-separated ICO sizes (default: 16,32,48)").option("--quality <n>","PNG compression 1-100 (higher = smaller file; PNG is lossless, default: 90)","90").action(async t=>{try{let r=process.cwd();l(Te.cyan(`
|
|
979
|
+
\u{1F3A8} Favicon Generator
|
|
980
|
+
`));let n=await si({source:t.path}),o=await Xc(r,t.out),i=vi(t.shape,Bc,"square","shape"),s=vi(t.fit,qc,"contain","fit"),a=Er(t.radius,20,"radius",0,50),p=Er(t.padding,0,"padding",0,30),d=Er(t.quality,90,"quality",1,100),u=Cr(t.sizes,[16,32,48]),h=t.bg??"transparent";Kc(h);let x=t.all===!0,k={source:n.source,outDir:o,force:!!t.force,dryRun:!!t.dryRun,emitIcon:!!t.icon||x,emitApple:!!t.apple||x,emitOg:!!t.og||x,emitTwitter:!!t.twitter,ogSource:t.ogSource,pwa:!!t.pwa,pwaInit:!!t.pwaInit,shape:i,radius:a,bg:h,padding:p,fit:s,icoSizes:u,quality:d};y.start("Generating favicon assets...");let z=await Tr(r,k);y.succeed(k.dryRun?"Favicon plan ready":"Favicon assets generated"),l("");for(let $ of z.outputs){let J=Rt.relative(r,$.path);$.skipped?l(Te.yellow(` \u21B7 skipped ${J} (exists; use --force to overwrite)`)):k.dryRun?l(Te.dim(` \u{1F4C4} would write ${J} (${wi($.bytes)})`)):l(Te.green(` \u2713 ${J} `)+Te.dim(`(${wi($.bytes)})`))}z.pwaSnippet&&(l(""),l(Te.cyan("Add this to your typed manifest (src/app/manifest.ts):")),l(Te.dim(z.pwaSnippet))),l("")}catch(r){y.fail("Favicon generation failed");let n=r instanceof Error?r.message:String(r);v(n),process.exit(1)}})},Xc=async(e,t)=>{if(t)return Rt.isAbsolute(t)?t:Rt.resolve(e,t);let r=await Et(e);return r||(Mr("Could not detect app/ or src/app/ \u2014 falling back to src/app"),Rt.join(e,"src","app"))},Wc=/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/,Yc=/^(?:rgb|rgba|hsl|hsla)\(\s*[\d.,%\s/]+\)$/i,Kc=e=>{if(e!=="transparent"&&!Wc.test(e)&&!Yc.test(e)&&!Pi.has(e.toLowerCase()))throw new Error(`Invalid value for --bg: '${e}'. Use 'transparent', a hex code (e.g. #0f172a), a CSS color name, or rgb()/rgba()/hsl()/hsla().`)},wi=e=>e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`;import Or from"node:path";import M from"picocolors";G();G();import fp from"node:path";import{readFile as Zc,writeFile as Qc}from"node:fs/promises";import ep from"node:path";var it=(e,t)=>{let r=/import\s+.*\s+from\s+['"].*['"];?\n/g,n=e.match(r);if(n&&n.length>0){let o=n[n.length-1],i=e.lastIndexOf(o);return e.slice(0,i+o.length)+t+`
|
|
981
|
+
`+e.slice(i+o.length)}return`${t}
|
|
982
|
+
${e}`},br=(e,t,r)=>{let n=/combineReducers\(\{([^}]*)\}\)/s,o=e.match(n);if(!o)throw new Error("Could not find combineReducers in rootReducer.ts");let i=o[1],s=`
|
|
983
|
+
${t}: ${r},`,a=i.trimEnd()+s;return e.replace(n,`combineReducers({${a}
|
|
984
|
+
})`)},st=(e,t)=>{let r=e.lastIndexOf("} as const;");if(r===-1)throw new Error("Could not find closing brace of AppApis object");let n=e.substring(0,r),o=e.substring(r);return`${n.trimEnd()}
|
|
985
|
+
${t}
|
|
986
|
+
${o}`};var at=async e=>{let{serviceName:t,projectPath:r}=e,n=O(t),o=ep.join(r,"src","lib","config","app-apis.ts");try{let i=await Zc(o,"utf-8");if(i.includes(`${n}:`))return;if(!i.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");let s=` ${n}: {
|
|
987
|
+
base: \`\${API_PREFIX}/${t}\`,
|
|
988
|
+
getAll: \`\${API_PREFIX}/${t}\`,
|
|
989
|
+
},`;i=st(i,s),await Qc(o,i)}catch(i){throw new Error(`Failed to register API endpoints: ${i}`,{cause:i})}};import{readFile as tp,writeFile as rp}from"node:fs/promises";import np from"node:path";P();var Rr=async(e,t,r)=>{let n=np.join(e,"src","lib","config","app-paths.ts");if(!m(n))return;let o=await tp(n,"utf-8"),i=O(t);if(o.includes(`${i}:`))return;let s=o.lastIndexOf("} as const;");if(s===-1)return;let a=` ${i}: '${r}',
|
|
990
|
+
`;o=o.slice(0,s)+a+o.slice(s),await rp(n,o)};S();P();import $t from"node:path";var op=e=>new RegExp(`<\\s*${e}\\b`),Ci=(e,t)=>{if(op(t).test(e))return e;let r=/^(?<indent>[ \t]*)\{children\}\s*$/m,n=e.match(r);if(!n||n.index===void 0)throw new Error("Could not locate `{children}` line in RootProvider \u2014 expected a line containing only `{children}`.");let o=n.groups?.indent??"",i=`${o} `,s=`${o}<${t}>
|
|
984
991
|
${i}{children}
|
|
985
|
-
${o}</${
|
|
986
|
-
`),o=[],i=[];for(let h of n)/^export \* from '\.\/.*';\s*$/.test(h)?o.push(h):i.push(h);let s=[...o,
|
|
987
|
-
${e.replace(/^\n+/,"")}`;let p=n.slice(0,a),d=n.findIndex((h,x)=>x>a&&!/^export \* from '\.\//.test(h)),
|
|
988
|
-
`)},
|
|
989
|
-
`))};var
|
|
992
|
+
${o}</${t}>`;return e.replace(r,s)},Ti=(e,t)=>{let r=`export * from './${t}';`;if(e.includes(r))return e;let n=e.split(`
|
|
993
|
+
`),o=[],i=[];for(let h of n)/^export \* from '\.\/.*';\s*$/.test(h)?o.push(h):i.push(h);let s=[...o,r].sort(),a=n.findIndex(h=>/^export \* from '\.\//.test(h));if(a===-1)return`${r}
|
|
994
|
+
${e.replace(/^\n+/,"")}`;let p=n.slice(0,a),d=n.findIndex((h,x)=>x>a&&!/^export \* from '\.\//.test(h)),u=d===-1?[]:n.slice(d);return[...p,...s,...u].join(`
|
|
995
|
+
`)},ip=c.PROVIDERS,sp=c.ROOT_PROVIDER,ap=c.PROVIDERS_INDEX,Ei=async(e,t={fileExists:m,readFile:f})=>{let r=$t.join(e,sp);if(t.fileExists(r))return r;let n=$t.join(e,ip);if(!t.fileExists(n))return null;let{readdir:o}=await import("node:fs/promises"),s=(await o(n).catch(()=>[])).filter(p=>p.endsWith(".tsx")),a=null;for(let p of s){let d=$t.join(n,p),u=await t.readFile(d);if(!/\{children\}/.test(u))continue;let x=((u.split("{children}")[0]??"").match(/<[A-Z][A-Za-z0-9_]*\b/g)??[]).length;(!a||x>a.depth)&&(a={file:d,depth:x})}return a?.file??null},$r=async e=>{let{projectPath:t,componentName:r,fileBaseName:n}=e,o=await Ei(t);if(o){let a=await f(o),p=a;(!/from '\.\//.test(a)||!a.includes(`{ ${r} }`))&&(p=it(p,`import { ${r} } from './${n}';`)),p=Ci(p,r),p!==a&&await g(o,p)}let i=$t.join(t,ap),s=null;if(m(i)){let a=await f(i),p=Ti(a,n);p!==a&&await g(i,p),s=i}return{rootProviderFile:o,barrelFile:s}};import{readFile as cp,writeFile as pp}from"node:fs/promises";import lp from"node:path";var ct=async e=>{let{projectPath:t,name:r,persist:n,importPath:o}=e,i=lp.join(t,"src","store","rootReducer.ts");try{let s=await cp(i,"utf-8"),a=O(r),p=`${a}Reducer`,d=`${a}PersistConfig`,u=o.replace(/^src\//,"@/"),h=n?`import { ${p}, ${d} } from '${u}';`:`import { ${p} } from '${u}';`;s=it(s,h);let x=n?`persistReducer(${d}, ${p})`:p;s=br(s,a,x),await pp(i,s)}catch(s){throw new Error(`Failed to register reducer '${r}' in rootReducer: ${s}`,{cause:s})}};P();import{readFile as mp,writeFile as dp}from"node:fs/promises";import up from"node:path";var Ir=async(e,t)=>{let r=up.join(e,"src","i18n","translations","en.json");if(!m(r))return;let n=await mp(r,"utf-8"),o=JSON.parse(n);o[t]||(o[t]={title:t,description:`${t} page description`},await dp(r,`${JSON.stringify(o,null,2)}
|
|
996
|
+
`))};var Nr=()=>[{name:"Project setup detected",spinnerText:"Detecting project setup...",execute:async e=>{e.detection=await A(e.projectPath)}},{name:"Feature files generated",spinnerText:"Generating feature files...",execute:async e=>{await Wt({name:e.featureName,outputPath:e.featurePath,createStore:e.createStore,persistStore:e.persistStore,createService:e.createService,httpClient:e.httpClient})}},{name:"API endpoints registered",spinnerText:"Registering API endpoints...",shouldSkip:e=>!e.createService,execute:async e=>{await at({serviceName:e.featureName,projectPath:e.projectPath})}},{name:"Feature registered in rootReducer",spinnerText:"Registering feature in rootReducer...",shouldSkip:e=>!e.createStore||!e.detection.hasRedux,execute:async e=>{await ct({projectPath:e.projectPath,name:e.featureName,persist:e.persistStore,importPath:fp.join(e.basePath,e.featureName,"store")})}}];var Ee=async(e,t)=>{for(let r of e)if(!r.shouldSkip?.(t)){t.spinner.start(r.spinnerText);try{await r.execute(t),t.spinner.succeed(r.name)}catch(n){throw t.spinner.fail(r.name),n}}};var kr=()=>[{name:"Service files generated",spinnerText:"Generating service files...",execute:async e=>{await Le({name:e.serviceName,outputPath:e.servicePath,httpClient:e.httpClient})}},{name:"API endpoints registered",spinnerText:"Registering API endpoints...",execute:async e=>{await at({serviceName:e.serviceName,projectPath:e.projectPath})}}];import gp from"node:path";var Ar=()=>[{name:"Slice files generated",spinnerText:"Generating slice files...",execute:async e=>{await He({name:e.sliceName,outputPath:e.slicePath,persist:e.persistSlice})}},{name:"Slice registered in rootReducer",spinnerText:"Registering slice in rootReducer...",execute:async e=>{await ct({projectPath:e.projectPath,name:e.sliceName,persist:e.persistSlice,importPath:gp.join(e.basePath,e.sliceName)})}}];import hp from"enquirer";var{prompt:yp}=hp,bi=async(e,t,r,n,o,i,s)=>{let a=[];e||a.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."}),t&&n===void 0&&o===void 0&&(a.push({type:"confirm",name:"createStore",message:"Generate Redux store for this feature?",initial:!0}),a.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&&s===void 0&&(a.push({type:"confirm",name:"createService",message:"Generate API service for this feature?",initial:!0}),r==="both"&&a.push({type:"select",name:"selectedHttpClient",message:"Which HTTP client to use for the service?",choices:["fetch","axios"],initial:0,skip(){return!this.state.answers.createService}}));let p=a.length>0?await yp(a):{};return{featureName:e||p.featureName,hasRedux:t||!1,createStore:n===!0?!1:o!==void 0?!0:p.createStore||!1,persistStore:o==="persist"?!0:o==="no-persist"?!1:p.persistStore||!1,httpClient:r||"none",createService:i===!0?!1:s!==void 0?!0:p.createService||!1,selectedHttpClient:s||p.selectedHttpClient||(r==="both"?"fetch":r!=="none"?r:void 0)}};var Ri=e=>{e.command("feature [name]").description("Generate a new feature module").option("--skip-store","Skip Redux store generation").option("--store <type>","Generate Redux store with persistence option (persist|no-persist)").option("--skip-service","Skip API service generation").option("--service <client>","Generate API service with specific HTTP client (axios|fetch)").option("--path <path>","Custom path for feature generation (default: src/features)").action(async(t,r)=>{try{let n=process.cwd();xp(r),l(M.cyan(`
|
|
990
997
|
\u{1F3AF} Feature Generator
|
|
991
|
-
`));let o=
|
|
992
|
-
`));let a=await
|
|
998
|
+
`));let o=Nr();y.start("Detecting project setup...");let{detectProjectSetup:i}=await Promise.resolve().then(()=>(G(),De)),s=await i(n);y.succeed("Project setup detected"),l(M.dim(` Redux: ${s.hasRedux?"\u2713":"\u2717"}`)),l(M.dim(` HTTP Client: ${s.httpClient}`)),l(M.dim(` i18n: ${s.hasI18n?"\u2713":"\u2717"}
|
|
999
|
+
`));let a=await bi(t,s.hasRedux,s.httpClient,r.skipStore,r.store,r.skipService,r.service),p=r.path||Or.join("src","features"),d=Or.join(n,p,a.featureName);await le(n,a.featureName,p)&&(v(`Feature '${a.featureName}' already exists at ${p}!`),process.exit(1)),await Ee(o.slice(1),{projectPath:n,spinner:y,featureName:a.featureName,basePath:p,featurePath:d,createStore:a.createStore,persistStore:a.persistStore,createService:a.createService,httpClient:a.selectedHttpClient,detection:s}),Pp(a,p)}catch(n){y.fail("Feature generation failed"),v(`${n}`),process.exit(1)}})},xp=e=>{e.store&&!["persist","no-persist"].includes(e.store)&&(v("Invalid --store option. Use: persist or no-persist"),process.exit(1)),e.service&&!["axios","fetch"].includes(e.service)&&(v("Invalid --service option. Use: axios or fetch"),process.exit(1)),e.skipStore&&e.store&&(v("Cannot use --skip-store and --store together"),process.exit(1)),e.skipService&&e.service&&(v("Cannot use --skip-service and --service together"),process.exit(1))},Pp=(e,t)=>{let r=Or.join(t,e.featureName);l(M.green(`
|
|
993
1000
|
\u2728 Feature '${e.featureName}' created successfully!
|
|
994
|
-
`)),l(
|
|
995
|
-
`)),l(
|
|
1001
|
+
`)),l(M.dim("Generated files:")),l(M.dim(` \u{1F4C2} ${r}/`)),l(M.dim(" \u251C\u2500\u2500 components/")),l(M.dim(" \u251C\u2500\u2500 hooks/")),l(M.dim(" \u251C\u2500\u2500 types/")),e.createStore&&l(M.dim(" \u251C\u2500\u2500 store/")),e.createService&&l(M.dim(" \u251C\u2500\u2500 services/")),l(M.dim(` \u2514\u2500\u2500 index.ts
|
|
1002
|
+
`)),l(M.cyan("Next steps:"));let n=t.replace(/^src\//,"@/");l(M.dim(` 1. Import and use the feature: import { ${e.featureName} } from '${n}/${e.featureName}'`)),e.createStore&&l(M.dim(` 2. Customize your Redux slice in: ${r}/store/`)),e.createService&&l(M.dim(` 3. Add API methods in: ${r}/services/${e.featureName}.service.ts`)),l("")};import Fr from"node:path";import Oe from"picocolors";G();import vp from"enquirer";var{prompt:wp}=vp,$i=async e=>e?{hookName:e}:await wp({type:"input",name:"hookName",message:'Hook name (kebab-case, without "use" prefix):',validate:r=>r?/^[a-z][a-z0-9-]*$/.test(r)?!0:"Use lowercase letters, numbers, and hyphens only":"Hook name is required"});var Ii=e=>{e.command("hook [name]").description("Generate a custom React hook").option("--client","Add 'use client' directive (default: true)",!0).option("--feature <path>","Generate in feature directory (e.g., src/features/auth)").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd();l(Oe.cyan(`
|
|
996
1003
|
\u{1FA9D} Hook Generator
|
|
997
|
-
`));let o=await
|
|
1004
|
+
`));let o=await A(n),i=await $i(t),a=`use${R(i.hookName)}`,p=Sp(r,o.hasTests);y.start("Generating hook..."),await Kt({name:i.hookName,projectPath:n,isClient:r.client??!0,featurePath:r.feature}),y.succeed("Hook generated");let d=r.feature?Fr.join(n,r.feature,"hooks",`${a}.ts`):Fr.join(n,"src/hooks",`${a}.ts`),u=null;p&&(y.start("Generating test..."),u=await oe({projectPath:n,sourceFile:d,kind:"hook",symbolName:a,hookUsesStore:o.hasRedux&&!!r.feature}),y.succeed("Test generated"));let h=r.feature?`${r.feature}/hooks/${a}.ts`:`src/hooks/${a}.ts`;l(Oe.green(`
|
|
998
1005
|
\u2728 Hook '${a}' created successfully!
|
|
999
|
-
`)),l(
|
|
1006
|
+
`)),l(Oe.dim(` \u{1F4C4} ${h}`)),u&&l(Oe.dim(` \u{1F9EA} ${Fr.relative(n,u)}`)),l(""),l(Oe.cyan("Usage:"));let x=r.feature?`${r.feature.replace(/^src\//,"@/")}/hooks/${a}`:`@/hooks/${a}`;l(Oe.dim(` import { ${a} } from '${x}';`)),l("")}catch(n){y.fail("Hook generation failed"),v(`${n}`),process.exit(1)}})},Sp=(e,t)=>e.noTest?!1:e.test?!0:t;import It from"picocolors";G();var Ni=e=>{e.command("layout <segment>").description("Generate a nested layout.tsx (locale-aware when i18n is detected)").option("--group","Treat the segment as a route group (wraps it in parens)").option("--at <path>","Place the layout under this nested path (kebab-case, slash-separated)").option("--no-locale","Skip the locale wrapper even if i18n is detected").action(async(t,r)=>{try{let n=process.cwd();l(It.cyan(`
|
|
1000
1007
|
\u{1F4D0} Layout Generator
|
|
1001
|
-
`)),y.start("Detecting project setup...");let o=await
|
|
1002
|
-
`)),y.start("Generating layout...");let s=await
|
|
1008
|
+
`)),y.start("Detecting project setup...");let o=await A(n);y.succeed("Project setup detected");let i=o.hasI18n&&r.locale!==!1;l(It.dim(` i18n: ${i?"\u2713":"\u2717"}
|
|
1009
|
+
`)),y.start("Generating layout...");let s=await Zt({segment:t,at:r.at,projectPath:n,hasI18n:i,withGroup:!!r.group});y.succeed("Layout generated"),l(It.green(`
|
|
1003
1010
|
\u2728 ${s.componentName} created!
|
|
1004
|
-
`)),l(
|
|
1011
|
+
`)),l(It.dim(` \u{1F4C4} ${s.displayPath}`)),l("")}catch(n){y.fail("Layout generation failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import Ep from"node:path";import re from"picocolors";P();G();import Cp from"enquirer";var{prompt:Tp}=Cp,ki=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"code",message:"Locale code (e.g., es, fr, de):",validate:o=>o?/^[a-z]{2}(-[A-Z]{2})?$/.test(o)?!0:"Use format: xx or xx-XX (e.g., es, pt-BR)":"Locale code is required"}),r.push({type:"input",name:"name",message:"Language name (e.g., Spanish, French):",validate:o=>o?!0:"Language name is required"},{type:"input",name:"country",message:"Country (e.g., Spain, France):",validate:o=>o?!0:"Country is required"},{type:"input",name:"flag",message:"Flag emoji (e.g., \u{1F1EA}\u{1F1F8}, \u{1F1EB}\u{1F1F7}):",validate:o=>o?!0:"Flag emoji is required"}),t.copyTranslations===void 0&&r.push({type:"confirm",name:"copyTranslations",message:"Copy translations from English? (No = empty values)",initial:!1});let n=await Tp(r);return{code:e??n.code,name:n.name,country:n.country,flag:n.flag,copyTranslations:t.copyTranslations??n.copyTranslations??!1}};var Ai=e=>{e.command("locale [code]").description("Add a new locale/language").option("--copy-translations","Copy translations from English instead of empty values").action(async(t,r)=>{try{let n=process.cwd();l(re.cyan(`
|
|
1005
1012
|
\u{1F30D} Locale Generator
|
|
1006
|
-
`)),y.start("Detecting project setup...");let o=await
|
|
1013
|
+
`)),y.start("Detecting project setup...");let o=await A(n);y.succeed("Project setup detected"),o.hasI18n||(y.fail("i18n is not set up in this project"),v("Please set up internationalization first"),l(re.dim(`
|
|
1007
1014
|
Run: npx @teispace/next-maker setup --i18n
|
|
1008
|
-
`)),process.exit(1));let i=await
|
|
1015
|
+
`)),process.exit(1));let i=await ki(t,{copyTranslations:r.copyTranslations}),s=Ep.join(n,"src","i18n","translations",`${i.code}.json`);m(s)&&(v(`Locale '${i.code}' already exists!`),process.exit(1)),y.start("Adding locale..."),await Qt({...i,projectPath:n}),y.succeed("Locale added"),l(re.green(`
|
|
1009
1016
|
\u2728 Locale '${i.code}' (${i.name}) added successfully!
|
|
1010
|
-
`)),l(
|
|
1017
|
+
`)),l(re.dim("Updated files:")),l(re.dim(` \u{1F4C4} src/i18n/translations/${i.code}.json`)),l(re.dim(" \u{1F4DD} src/types/i18n.ts (SupportedLocale type)")),l(re.dim(" \u{1F4DD} src/lib/config/app-locales.ts")),l(""),l(re.cyan("Next steps:")),l(re.dim(` 1. Translate: src/i18n/translations/${i.code}.json`)),l(re.dim(` 2. Visit: http://localhost:3000/${i.code}`)),l("")}catch(n){y.fail("Locale generation failed"),v(`${n}`),process.exit(1)}})};import Fi from"node:path";import Y from"picocolors";G();import bp from"enquirer";var{prompt:Rp}=bp,Oi=async(e,t={})=>{let r=[];e||r.push({type:"input",name:"pageName",message:"Page name (kebab-case):",validate:o=>o?/^[a-z][a-z0-9-]*$/.test(o)?!0:"Use lowercase letters, numbers, and hyphens only":"Page name is required"}),t.loading===void 0&&r.push({type:"confirm",name:"withLoading",message:"Generate loading.tsx?",initial:!0}),t.error===void 0&&r.push({type:"confirm",name:"withError",message:"Generate error.tsx?",initial:!0});let n=r.length>0?await Rp(r):{};return{pageName:e??n.pageName,withLoading:t.loading??n.withLoading??!0,withError:t.error??n.withError??!0}};var _i=e=>{e.command("page [name]").description("Generate a new page/route").option("--dynamic <param>","Create dynamic route with parameter (e.g., id)").option("--loading","Generate loading.tsx").option("--error","Generate error.tsx").action(async(t,r)=>{try{let n=process.cwd();l(Y.cyan(`
|
|
1011
1018
|
\u{1F4C4} Page Generator
|
|
1012
|
-
`)),y.start("Detecting project setup...");let o=await
|
|
1013
|
-
`));let i=await
|
|
1019
|
+
`)),y.start("Detecting project setup...");let o=await A(n);y.succeed("Project setup detected"),l(Y.dim(` i18n: ${o.hasI18n?"\u2713":"\u2717"}
|
|
1020
|
+
`));let i=await Oi(t,{loading:r.loading,error:r.error}),s=i.pageName,a=R(s),p=o.hasI18n?"src/app/[locale]":"src/app";await le(n,s,p)&&(v(`Page '${s}' already exists at ${p}/${s}!`),process.exit(1)),y.start("Generating page files..."),await tr({name:s,projectPath:n,hasI18n:o.hasI18n,dynamic:r.dynamic,withLoading:r.loading??i.withLoading,withError:r.error??i.withError}),y.succeed("Page files generated"),y.start("Registering route...");let u=r.dynamic?`/${s}/[${r.dynamic}]`:`/${s}`;await Rr(n,s,u),y.succeed("Route registered"),o.hasI18n&&(y.start("Adding translation namespace..."),await Ir(n,a),y.succeed("Translation namespace added"));let h=r.dynamic?Fi.join(p,s,`[${r.dynamic}]`):Fi.join(p,s);l(Y.green(`
|
|
1014
1021
|
\u2728 Page '${s}' created successfully!
|
|
1015
|
-
`)),l(
|
|
1022
|
+
`)),l(Y.dim("Generated files:")),l(Y.dim(` \u{1F4C2} ${h}/`)),l(Y.dim(" \u251C\u2500\u2500 page.tsx")),(r.loading??i.withLoading)&&l(Y.dim(" \u251C\u2500\u2500 loading.tsx")),(r.error??i.withError)&&l(Y.dim(" \u2514\u2500\u2500 error.tsx")),l(""),o.hasI18n&&(l(Y.cyan("Next steps:")),l(Y.dim(` 1. Add translations in: src/i18n/translations/en.json \u2192 "${a}"`)),l(Y.dim(` 2. Visit: http://localhost:3000/${s}`)),l(""))}catch(n){y.fail("Page generation failed"),v(`${n}`),process.exit(1)}})};import _r from"node:path";import fe from"picocolors";var ji=e=>{e.command("provider <name>").description("Generate a context provider in src/providers/ and wire it into RootProvider").action(async t=>{try{let r=process.cwd();l(fe.cyan(`
|
|
1016
1023
|
\u{1F50C} Provider Generator
|
|
1017
|
-
`)),y.start("Generating provider...");let{componentName:n,fileBaseName:o,providerFile:i}=await
|
|
1024
|
+
`)),y.start("Generating provider...");let{componentName:n,fileBaseName:o,providerFile:i}=await nr({name:t,projectPath:r});y.succeed("Provider generated"),y.start("Registering provider in RootProvider and barrel...");let{rootProviderFile:s,barrelFile:a}=await $r({projectPath:r,componentName:n,fileBaseName:o});y.succeed("Provider registered"),l(fe.green(`
|
|
1018
1025
|
\u2728 ${n} created!
|
|
1019
|
-
`)),l(
|
|
1020
|
-
\u26A0\uFE0F Could not locate a RootProvider file. Wire the new provider manually:`)),l(
|
|
1026
|
+
`)),l(fe.dim("Generated files:")),l(fe.dim(` \u{1F4C4} ${_r.relative(r,i)}`)),s?l(fe.dim(` \u270F\uFE0F ${_r.relative(r,s)} \u2014 wrapped {children}`)):(l(fe.yellow(`
|
|
1027
|
+
\u26A0\uFE0F Could not locate a RootProvider file. Wire the new provider manually:`)),l(fe.dim(` <${n}>{children}</${n}>`))),a&&l(fe.dim(` \u270F\uFE0F ${_r.relative(r,a)} \u2014 added re-export`)),l("")}catch(r){y.fail("Provider generation failed"),v(`${r instanceof Error?r.message:r}`),process.exit(1)}})};import $p from"enquirer";import H from"picocolors";var{prompt:Ip}=$p,Np=e=>{let t=[];for(let r of e.filesRemoved)t.push(` ${H.red("-")} delete: ${r}`);for(let r of e.blocksStripped)t.push(` ${H.red("-")} strip block: ${r.description} ${H.dim(`(${r.file})`)}`);for(let r of e.scriptsRemoved)t.push(` ${H.red("-")} remove script: ${r}`);for(let r of e.packagesUninstalled)t.push(` ${H.red("-")} uninstall: ${r}`);for(let r of e.manualCleanup)t.push(` ${H.yellow("?")} manual cleanup: ${r.description} ${H.dim(`(${r.file})`)}`);return t},kp=e=>e.filesRemoved.length===0&&e.blocksStripped.length===0&&e.scriptsRemoved.length===0&&e.packagesUninstalled.length===0&&e.manualCleanup.length===0,Di=e=>{e.command("remove <feature>").alias("uninstall").description("Reverse a feature install (uses the feature manifest)").option("-y, --yes","Skip confirmation prompt").option("--dry-run","Show what would change without writing").action(async(t,r)=>{try{let n=process.cwd(),o=Yo(t);if(!o)throw new Error(`Unknown feature "${t}". Valid: ${Se.map(p=>p.id).join(", ")}.`);if(l(H.cyan(`
|
|
1021
1028
|
\u{1F5D1} Remove ${o.name}
|
|
1022
|
-
`)),!(await
|
|
1029
|
+
`)),!(await nt(o,n)).installed){l(H.dim(`${o.name} is not installed \u2014 nothing to remove.`));return}y.start("Computing changes...");let s=await Tt(o,n,{dryRun:!0});if(y.succeed("Computed plan"),kp(s)){l(H.yellow(`
|
|
1023
1030
|
\u26A0\uFE0F Manifest had no removable artifacts. Nothing to do.
|
|
1024
|
-
`));return}l(
|
|
1031
|
+
`));return}l(H.bold(`
|
|
1025
1032
|
Planned changes:
|
|
1026
|
-
`));for(let p of
|
|
1027
|
-
`));return}if(!
|
|
1033
|
+
`));for(let p of Np(s))l(p);if(l(""),r.dryRun){l(H.dim(`--dry-run set \u2014 exiting without writing.
|
|
1034
|
+
`));return}if(!r.yes){let{confirm:p}=await Ip({type:"confirm",name:"confirm",message:`Apply the changes above to remove ${o.name}?`,initial:!1});if(!p){l(H.yellow(`
|
|
1028
1035
|
Aborted.
|
|
1029
|
-
`));return}}y.start(`Removing ${o.name}...`);let a=o.remove?(await o.remove(n),s):await
|
|
1030
|
-
\u2713 ${o.name} removed.`)),a.manualCleanup.length>0){l(
|
|
1031
|
-
\u26A0\uFE0F Manual cleanup still required:`));for(let p of a.manualCleanup)l(` - ${p.description} (${p.file})`)}l("")}catch(n){y.fail("Remove failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import{existsSync as
|
|
1036
|
+
`));return}}y.start(`Removing ${o.name}...`);let a=o.remove?(await o.remove(n),s):await Tt(o,n);if(y.succeed(`${o.name} removed`),l(H.green(`
|
|
1037
|
+
\u2713 ${o.name} removed.`)),a.manualCleanup.length>0){l(H.yellow(`
|
|
1038
|
+
\u26A0\uFE0F Manual cleanup still required:`));for(let p of a.manualCleanup)l(` - ${p.description} (${p.file})`)}l("")}catch(n){y.fail("Remove failed"),v(`${n instanceof Error?n.message:n}`),process.exit(1)}})};import{existsSync as _p}from"node:fs";import{mkdir as jp}from"node:fs/promises";import pt from"node:path";import K from"picocolors";G();import{readFile as Ap,writeFile as Op}from"node:fs/promises";import Fp from"node:path";var Li=async(e,t)=>{let r=O(t),n=Fp.join(e,"src","lib","config","app-apis.ts");try{let o=await Ap(n,"utf-8");if(o.includes(`${r}:`))return;if(!o.match(/export const AppApis = \{[\s\S]*?\} as const;/))throw new Error("Could not find AppApis object in app-apis.ts");let i=Tn({camelName:r,kebabName:t});o=st(o,i),await Op(n,o)}catch(o){throw new Error(`Failed to register CRUD API endpoints: ${o}`,{cause:o})}};import Mi from"enquirer";var Gi=async(e,t,r,n)=>{let o=e||(await Mi.prompt({type:"input",name:"serviceName",message:"Service name (kebab-case):",validate:s=>s?/^[a-z0-9-]+$/.test(s)?!0:"Service name must be lowercase with hyphens only":"Service name is required"})).serviceName,i;return t!==void 0?i="axios":r!==void 0?i="fetch":n==="axios"?i="axios":n==="fetch"?i="fetch":n==="both"?i=(await Mi.prompt({type:"select",name:"httpClient",message:"Choose HTTP client:",choices:["axios","fetch"]})).httpClient:i="axios",{serviceName:o,httpClient:i}};var Hi=e=>{e.command("service [name]").description("Generate an API service").option("--path <path>","Custom path for service generation (default: create new feature)").option("--axios","Use Axios HTTP client").option("--fetch","Use Fetch HTTP client").option("--crud","Generate full CRUD service (getAll, getById, create, update, delete)").action(async(t,r)=>{try{let n=process.cwd();r.axios&&r.fetch&&(v("Cannot use --axios and --fetch together"),process.exit(1)),l(K.cyan(`
|
|
1032
1039
|
\u{1F527} Service Generator
|
|
1033
|
-
`)),y.start("Detecting project setup...");let o=await
|
|
1040
|
+
`)),y.start("Detecting project setup...");let o=await A(n);y.succeed("Project setup detected"),o.httpClient==="none"&&(y.fail("No HTTP client is setup in this project"),v("Please setup either AxiosClient or FetchClient first"),l(K.dim(`
|
|
1034
1041
|
Check: lib/utils/http/axios-client or lib/utils/http/fetch-client
|
|
1035
|
-
`)),process.exit(1));let i=[];(o.httpClient==="axios"||o.httpClient==="both")&&i.push("Axios \u2713"),(o.httpClient==="fetch"||o.httpClient==="both")&&i.push("Fetch \u2713"),l(
|
|
1036
|
-
`));let s=await
|
|
1037
|
-
\u2728 ${
|
|
1038
|
-
`)),l(
|
|
1039
|
-
`)),l(
|
|
1042
|
+
`)),process.exit(1));let i=[];(o.httpClient==="axios"||o.httpClient==="both")&&i.push("Axios \u2713"),(o.httpClient==="fetch"||o.httpClient==="both")&&i.push("Fetch \u2713"),l(K.dim(` HTTP Clients: ${i.join(", ")}
|
|
1043
|
+
`));let s=await Gi(t,r.axios,r.fetch,o.httpClient),{basePath:a,servicePath:p}=Dp(n,s.serviceName,r.path);_p(p)||await jp(p,{recursive:!0}),ft(n,a,`${s.serviceName}.service.ts`)&&(v(`Service '${s.serviceName}' already exists at ${a}!`),process.exit(1)),r.crud?(y.start("Generating CRUD service files..."),await Xt({name:s.serviceName,outputPath:p,httpClient:s.httpClient}),y.succeed("CRUD service files generated"),y.start("Registering CRUD API endpoints..."),await Li(n,s.serviceName),y.succeed("CRUD API endpoints registered")):await Ee(kr(),{projectPath:n,spinner:y,serviceName:s.serviceName,servicePath:p,httpClient:s.httpClient}),Lp(s,a,!!r.crud)}catch(n){y.fail("Service generation failed"),v(`${n}`),process.exit(1)}})},Dp=(e,t,r)=>{let n;if(r){let o=r.replace(/^src\//,"");if(o.startsWith("features/")){let i=o.split("/")[1];n=pt.join("src","features",i,"services")}else n=pt.join("src",o)}else n=pt.join("src","features",t,"services");return{basePath:n,servicePath:pt.join(e,n)}},Lp=(e,t,r=!1)=>{let n=pt.join(t,`${e.serviceName}.service.ts`);l(K.green(`
|
|
1044
|
+
\u2728 ${r?"CRUD ":""}Service '${e.serviceName}' created successfully!
|
|
1045
|
+
`)),l(K.dim("Generated files:")),l(K.dim(` \u{1F4C4} ${n}
|
|
1046
|
+
`)),l(K.cyan("Next steps:"));let o=t.replace(/^src\//,"@/");l(K.dim(` 1. Import service: import { ${e.serviceName}Service } from '${o}/${e.serviceName}.service'`)),r?(l(K.dim(" 2. Available methods: getAll, getById, create, update, delete")),l(K.dim(" 3. Update DTO types in the service file"))):l(K.dim(` 2. Use in component: const data = await ${e.serviceName}Service.getAll()`)),l("")};import Mp from"enquirer";import jr from"picocolors";var{prompt:Gp}=Mp,Ui=e=>{e.command("setup").description("Setup features in an existing Next.js project").option("--http-client","Setup HTTP client (axios|fetch)").option("--dark-theme","Setup Dark Theme (Tailwind + @teispace/next-themes)").option("--redux","Setup Redux Toolkit").option("--i18n","Setup next-intl for internationalization").option("--tests","Setup testing (Vitest + React Testing Library)").option("--react-compiler","Enable the React Compiler").option("--bundle-analyzer","Add @next/bundle-analyzer").option("--security-headers","Add hardened HTTP headers to next.config.ts").option("--validate-scripts","Add scripts/sync-env.ts, scripts/check-deprecated.ts, and the validate chain").option("--commitizen","Add Commitizen with the conventional-changelog adapter").action(async t=>{try{if(l(jr.cyan(`
|
|
1040
1047
|
\u{1F527} Setup Wizard
|
|
1041
|
-
`)),
|
|
1042
|
-
\u26A0\uFE0F ${o} setup is not implemented yet.`))}catch(
|
|
1048
|
+
`)),t.httpClient||t.darkTheme||t.redux||t.i18n||t.tests||t.reactCompiler||t.bundleAnalyzer||t.securityHeaders||t.validateScripts||t.commitizen){t.httpClient&&await Ye(process.cwd()),t.darkTheme&&await Xe(process.cwd()),t.redux&&await Qe(process.cwd()),t.i18n&&await Ke(process.cwd()),t.tests&&await tt(process.cwd()),t.reactCompiler&&await Ze(process.cwd()),t.bundleAnalyzer&&await Ve(process.cwd()),t.securityHeaders&&await et(process.cwd()),t.validateScripts&&await rt(process.cwd()),t.commitizen&&await Be(process.cwd());return}let o=(await Gp([{type:"select",name:"feature",message:"What would you like to setup?",choices:[{name:"Dark Theme",value:"dark-theme"},{name:"Redux Toolkit",value:"redux"},{name:"HTTP Client (Axios/Fetch)",value:"http-client"},{name:"Internationalization (next-intl)",value:"i18n"},{name:"Testing (Vitest + RTL)",value:"tests"},{name:"React Compiler",value:"react-compiler"},{name:"Bundle Analyzer",value:"bundle-analyzer"},{name:"Security Headers",value:"security-headers"},{name:"Validation Scripts",value:"validate-scripts"},{name:"Commitizen",value:"commitizen"},"Cancel"]}])).feature;if(o==="Cancel"){l(jr.yellow("Setup cancelled."));return}let s={"dark-theme":Xe,redux:Qe,"http-client":Ye,i18n:Ke,tests:tt,"react-compiler":Ze,"bundle-analyzer":Ve,"security-headers":et,"validate-scripts":rt,commitizen:Be}[o];s?await s(process.cwd()):l(jr.yellow(`
|
|
1049
|
+
\u26A0\uFE0F ${o} setup is not implemented yet.`))}catch(r){y.fail("Setup failed"),v(`${r}`),process.exit(1)}})};import{existsSync as zp}from"node:fs";import{mkdir as Jp}from"node:fs/promises";import ge from"node:path";import U from"picocolors";G();import Hp from"enquirer";var{prompt:Up}=Hp,zi=async(e,t,r)=>{let n=[];e||n.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."}),t===void 0&&r===void 0&&n.push({type:"confirm",name:"persistSlice",message:"Enable persistence for this slice?",initial:!1});let o=n.length>0?await Up(n):{};return{sliceName:e||o.sliceName,persistSlice:t===!0?!0:r===!1?!1:o.persistSlice||!1}};var Ji=e=>{e.command("slice [name]").description("Generate a Redux slice").option("--path <path>","Custom path for slice generation (default: create new feature)").option("--persist","Enable persistence for this slice").option("--no-persist","Disable persistence for this slice").option("--test","Also generate a sibling test file").option("--no-test","Skip test file generation").action(async(t,r)=>{try{let n=process.cwd();r.persist&&r.noPersist===!0&&(v("Cannot use --persist and --no-persist together"),process.exit(1)),l(U.cyan(`
|
|
1043
1050
|
\u{1F527} Slice Generator
|
|
1044
|
-
`)),y.start("Detecting project setup...");let o=await
|
|
1051
|
+
`)),y.start("Detecting project setup...");let o=await A(n);y.succeed("Project setup detected"),o.hasRedux||(y.fail("Redux is not setup in this project"),v("Please install @reduxjs/toolkit and react-redux first"),l(U.dim(`
|
|
1045
1052
|
Run: npm install @reduxjs/toolkit react-redux
|
|
1046
|
-
`)),process.exit(1)),l(
|
|
1047
|
-
`));let i=await
|
|
1053
|
+
`)),process.exit(1)),l(U.dim(` Redux: \u2713
|
|
1054
|
+
`));let i=await zi(t,r.persist,r.noPersist===!0?!1:void 0),{basePath:s,slicePath:a}=Vp(n,i.sliceName,r.path),p=ge.join(n,s);zp(p)||await Jp(p,{recursive:!0}),await le(n,i.sliceName,s)&&(v(`Slice '${i.sliceName}' already exists at ${s}!`),process.exit(1)),await Ee(Ar(),{projectPath:n,spinner:y,sliceName:i.sliceName,basePath:s,slicePath:a,persistSlice:i.persistSlice});let u=null;if(Bp(r,o.hasTests)){let x=ge.join(a,`${i.sliceName}.slice.ts`);y.start("Generating test..."),u=await oe({projectPath:n,sourceFile:x,kind:"slice",symbolName:O(i.sliceName)}),y.succeed("Test generated")}qp(i,s,u,n)}catch(n){y.fail("Slice generation failed"),v(`${n}`),process.exit(1)}})},Vp=(e,t,r)=>{let n;if(r){let o=r.replace(/^src\//,"");if(o.startsWith("features/")){let i=o.split("/")[1];n=ge.join("src","features",i,"store")}else n=ge.join("src",o)}else n=ge.join("src","features",t,"store");return{basePath:n,slicePath:ge.join(e,n,t)}},Bp=(e,t)=>e.noTest?!1:e.test?!0:t,qp=(e,t,r,n)=>{let o=ge.join(t,e.sliceName);l(U.green(`
|
|
1048
1055
|
\u2728 Slice '${e.sliceName}' created successfully!
|
|
1049
|
-
`)),l(
|
|
1050
|
-
`)),
|
|
1051
|
-
`)),l(
|
|
1052
|
-
Infers the kind from filename/content; pass --kind to override.`).option("--kind <kind>","Override inferred kind: component | hook | slice").option("--force","Overwrite an existing test file").action(async(r
|
|
1056
|
+
`)),l(U.dim("Generated files:")),l(U.dim(` \u{1F4C2} ${o}/`)),l(U.dim(` \u251C\u2500\u2500 ${e.sliceName}.slice.ts`)),l(U.dim(` \u251C\u2500\u2500 ${e.sliceName}.selectors.ts`)),e.persistSlice&&l(U.dim(" \u251C\u2500\u2500 persist.ts")),l(U.dim(` \u251C\u2500\u2500 ${e.sliceName}.types.ts`)),l(U.dim(` \u2514\u2500\u2500 index.ts
|
|
1057
|
+
`)),r&&l(U.dim(` \u{1F9EA} ${ge.relative(n,r)}
|
|
1058
|
+
`)),l(U.cyan("Next steps:"));let i=t.replace(/^src\//,"@/");l(U.dim(` 1. Import actions: import { setLoading, setError } from '${i}/${e.sliceName}'`)),l(U.dim(" 2. Use in component: dispatch(setLoading(true))")),l("")};import Z from"node:path";import Dr from"picocolors";P();G();var Vi=e=>{e.command("test <file>").description(`Generate a sibling test file for an existing component, hook, or slice.
|
|
1059
|
+
Infers the kind from filename/content; pass --kind to override.`).option("--kind <kind>","Override inferred kind: component | hook | slice").option("--force","Overwrite an existing test file").action(async(t,r)=>{try{let n=process.cwd(),o=Z.isAbsolute(t)?t:Z.join(n,t);l(Dr.cyan(`
|
|
1053
1060
|
\u{1F9EA} Test Generator
|
|
1054
|
-
`)),m(o)||(v(`Source file not found: ${
|
|
1055
|
-
\u2728 Test '${
|
|
1056
|
-
`)),l(
|
|
1061
|
+
`)),m(o)||(v(`Source file not found: ${t}`),process.exit(1));let i=await A(n);i.hasTests||(v("Testing is not installed in this project. Run `next-maker setup --tests` first."),process.exit(1));let s=await f(o),a=Xp(r.kind)??Wp(o,s);a||(v(`Could not infer test kind for ${Z.basename(o)}. Pass --kind component|hook|slice.`),process.exit(1));let p=Yp(o,a),d=Kp(o,a);m(d)&&!r.force&&(v(`Test file already exists: ${Z.relative(n,d)}. Use --force to overwrite.`),process.exit(1)),y.start(`Generating ${a} test...`);let u=await oe({projectPath:n,sourceFile:o,kind:a,symbolName:p,hasRedux:i.hasRedux,hasI18n:i.hasI18n,hookUsesStore:a==="hook"&&i.hasRedux&&s.includes("useAppSelector")});y.succeed("Test generated"),l(Dr.green(`
|
|
1062
|
+
\u2728 Test '${Z.basename(u)}' created.
|
|
1063
|
+
`)),l(Dr.dim(` \u{1F9EA} ${Z.relative(n,u)}`)),l("")}catch(n){y.fail("Test generation failed"),v(`${n}`),process.exit(1)}})},Xp=e=>{if(!e)return null;if(e==="component"||e==="hook"||e==="slice")return e;throw new Error(`Invalid --kind: ${e}. Use component | hook | slice.`)},Wp=(e,t)=>{let r=Z.basename(e);return/\.slice\.ts$/.test(r)?"slice":/^use[A-Z]/.test(r.replace(/\.tsx?$/,""))?"hook":r.endsWith(".tsx")?"component":/createSlice\s*\(/.test(t)?"slice":/^export\s+(const|function)\s+use[A-Z]/m.test(t)?"hook":null},Yp=(e,t)=>{let r=Z.basename(e).replace(/\.(tsx?|jsx?)$/i,"");return t==="slice"?O(r.replace(/\.slice$/,"")):t==="hook"?/^use[A-Z]/.test(r)?r:`use${R(r.replace(/^use-?/,""))}`:R(r)},Kp=(e,t)=>{let r=Z.dirname(e),n=Z.basename(e).replace(/\.(tsx?|jsx?)$/i,""),o=t==="component"?".tsx":".ts";return Z.join(r,`${n}.test${o}`)};var Bi=e=>{yn(e),Ui(e),Ri(e),Ji(e),Hi(e),_i(e),Ni(e),Xn(e),Ai(e),Ii(e),ji(e),ii(e),Si(e),Ko(e),Di(e),Vi(e)};var Qp=process.emitWarning;process.emitWarning=function(e,t,r,n){if(!(typeof e=="string"&&e.includes("--localstorage-file")&&e.includes("was provided without a valid path")))return Qp.apply(process,arguments)};async function el(){Lr({logger:t=>lt(t)});let e=new Zp;e.name("next-maker").description("Teispace Next.js Project Generator").version("1.0.0"),Bi(e),e.parse()}el().catch(e=>{let t=e&&typeof e=="object"&&"message"in e?e.message:String(e);lt(`Unexpected error: ${t}`)});
|
|
1057
1064
|
//# sourceMappingURL=index.js.map
|