@bgscore/react-router
Version:
Automatic React Router generator for Vite with TypeScript support
2 lines (1 loc) • 9.82 kB
JavaScript
;Object.defineProperty(exports,"t",{value:!0});var t=require("path"),e=require("fs"),r=require("fs/promises");function n(t,e,{baseUrl:r,authGuardDir:n,notFoundDir:o}){function a(t,o,s=!1){const c=" ".repeat(o),i=[];if(i.push(`${c}{`),t.isIndex?i.push(`${c} index: true,`):i.push(`${c} path: "${t.path}",`),t.element){let e=`<${t.element} />`;const r=t.imports.some((t=>"layout"===t.type));if(n&&!r&&(e=`<AuthGuard>${e}</AuthGuard>`),i.push(`${c} element: ${e},`),t.hasErrorBoundary&&r){const e=t.imports.find((t=>"layout"===t.type));e&&(i.push(`${c} errorElement: (async () => {`),i.push(`${c} const mod = await import("${e.path}");`),i.push(`${c} const rawErrorElement = mod.metadata?.errorElement;`),i.push(`${c} if (React.isValidElement(rawErrorElement)) {`),i.push(`${c} return rawErrorElement;`),i.push(`${c} } else if (typeof rawErrorElement === 'function') {`),i.push(`${c} return React.createElement(React.Suspense, { fallback: React.createElement('div', null, '') }, React.createElement(rawErrorElement));`),i.push(`${c} } else {`),i.push(`${c} return null;`),i.push(`${c} }`),i.push(`${c} })(),`))}}const u=t.imports.find((t=>"component"===t.type));if(u&&e.find((t=>t.path===u.path))){const e=function(t,e){return t.replace(new RegExp(`^${e}/?`),"").replace(/\[(.+?)\]/g,((t,e)=>e)).replace(/\//g,"-").toLowerCase()}(u.path,r);i.push(`${c} id: "${e}",`),i.push(`${c} loader: async (...props) => {`),i.push(`${c} const mod = await import("${u.path}");`),i.push(`${c} const { errorElement, ...metadata } = mod.metadata ?? {};`),i.push(`${c} return {`),i.push(`${c} metadata,`),i.push(`${c} data: mod.metadata?.loader ? await mod.metadata.loader(...props) : undefined`),i.push(`${c} };`),i.push(`${c} },`),t.hasErrorBoundary&&(i.push(`${c} errorElement: (async () => {`),i.push(`${c} const mod = await import("${u.path}");`),i.push(`${c} const rawErrorElement = mod.metadata?.errorElement;`),i.push(`${c} if (React.isValidElement(rawErrorElement)) {`),i.push(`${c} return rawErrorElement;`),i.push(`${c} } else if (typeof rawErrorElement === 'function') {`),i.push(`${c} return React.createElement(React.Suspense, { fallback: React.createElement('div', null, '') }, React.createElement(rawErrorElement));`),i.push(`${c} } else {`),i.push(`${c} return null;`),i.push(`${c} }`),i.push(`${c} })(),`))}return t.children.length>0&&(i.push(`${c} children: [`),t.children.forEach(((e,r)=>{const n=a(e,o+4,!1);i.push(n+(r<t.children.length-1?",":""))})),i.push(`${c} ]`)),i.push(`${c}}`),i.join("\n")}let s=t.map((t=>a(t,2,!0))).join(",\n");return o&&(s+=',\n { path: "*", element: <NotFound /> }'),`[\n${s}\n]`}function o(e,r){return t.relative(r,e).split(t.sep).map((t=>{let e=t.replace(/\.tsx$/,"")?.trim();return e=e.replace(/\s+/g,"_").replace(/\[(\w+)\]/g,((t,e)=>e.charAt(0).toUpperCase()+e.slice(1))),"index"===e?"Index":e})).filter(Boolean).join("-").split(/[\/\-_]/).map((t=>t.charAt(0).toUpperCase()+t.slice(1))).join("")}function a(t){try{return e.readFileSync(t,"utf-8").includes("export const metadata")}catch{return!1}}function s(t){try{const r=e.readFileSync(t,"utf-8"),n=/export\s+const\s+metadata\s*:\s*.*?\s*=\s*({[\s\S]*?})?/,o=r.match(n);if(o){const t=o[1].replace(/(\n|\r|\t| )/g,"");return{independent:t.includes("independent:true"),layout:!t.includes("layout:false")}}return{independent:!1,layout:!0}}catch{return{independent:!1,layout:!0}}}function c(t,e){const r={...t[0],children:[]};let n=r;for(let e=1;e<t.length;e++){const r={...t[e],children:[]};n.children=[r],n=r}return n.children=[e],r}function i(t){return t.startsWith("[")&&t.endsWith("]")?`:${t.slice(1,-1)}`:t}function u(r,n,l,m,d){let p=[];const f=e.readdirSync(r).sort(((t,e)=>t===`${m}.tsx`?-1:e===`${m}.tsx`?1:t.localeCompare(e))),$=d.slice(),h=f.find((t=>t===`${m}.tsx`));let y=d.slice();if(h){const a=t.join(r,h),s=o(a,n),c=`${l}/${t.relative(n,a).replace(/\.tsx$/,"").replace(/\\/g,"/")}`,u=r===n?"/":i(t.basename(r));let m=!1,d=!1,p=!1;if(e.statSync(a).isFile()){const t=e.readFileSync(a,"utf8").match(/export\s+const\s+metadata\s*(?:\:\s*[\w\<\>\[\]]+)?\s*=\s*\{([\s\S]*?)\}/m);if(t){const e=[...t[1].matchAll(/([a-zA-Z0-9_]+)\s*:/g)].map((t=>t[1]));p=e.includes("metadata"),m=e.includes("errorElement"),d=e.includes("loader")}}const f={path:u,element:s,children:[],isIndex:!1,imports:[{name:s,path:c,type:"layout"}],hasErrorBoundary:m,hasMetadata:p,hasLoader:d};y=y.concat(f)}else if(r!==n){const e={path:i(t.basename(r)),children:[],imports:[],isIndex:!1};y=y.concat(e)}for(const d of f){const f=t.join(r,d),h=e.statSync(f);let E=!1,g=!1,w=!1;if(h.isFile()){const t=e.readFileSync(f,"utf8").match(/export\s+const\s+metadata\s*(?:\:\s*[\w\<\>\[\]]+)?\s*=\s*\{([\s\S]*?)\}/m);if(t){const e=[...t[1].matchAll(/([a-zA-Z0-9_]+)\s*:/g)].map((t=>t[1]));w=e.includes("metadata"),E=e.includes("errorElement"),g=e.includes("loader")}}if(h.isFile()&&".tsx"===t.extname(d)&&d!==`${m}.tsx`&&"root.tsx"!==d){const e=t.basename(d,".tsx"),u="index"===e,m=e.startsWith("[")&&e.endsWith("]"),h=u?"":m?`:${e.slice(1,-1)}`:e,x=s(f),{independent:R=!1,layout:D=!0}=x,A=o(f,n),I={path:h,isIndex:u,element:A,children:[],imports:[{name:A,path:`${l}/${t.relative(n,f).replace(/\.tsx$/,"").replace(/\\/g,"/")}`,type:"component",hasMetadata:a(f)}],isIndependent:R,metadata:x,hasErrorBoundary:E,hasMetadata:w,hasLoader:g},b=!1===D&&y.length>$.length?$.concat({path:r===n?"/":i(t.basename(r)),children:[],imports:[],isIndex:!1}):y;if(R){const t=b.length?b[b.length-1]:null,e={path:b.map((t=>t.path)).filter((t=>"/"!==t)).join("/").replace(/\/+/g,"/")||(u?"":h),element:t?t.element:void 0,children:[I],imports:t?t.imports:[],isIndex:!1};p.push(e)}else{const t=b.length>0?c(b,I):I;p.push(t)}}else if(h.isDirectory()){const t=u(f,n,l,m,y);p=p.concat(t)}}return p}function l(t,e){return t.map((t=>{const r={...t,imports:t.imports?[...t.imports]:[],children:t.children?t.children.map((t=>({...t}))):[]};if(r.children&&r.children.length>0&&(r.children=l(r.children,e),1===r.children.length&&r.children[0].isIndex,!r.children.some((t=>"*"===t.path)))){r.imports.some((t=>"NotFound"===t.name))||r.imports.push({name:"NotFound",path:e,type:"component"});const t={path:"*",element:"NotFound",children:[],imports:[],isIndex:!1};r.children=[...r.children,t]}return r}))}function m(t,e,r,n,o){const a=u(e,t,r,n,[]);let s=[];return o&&(s=l(a,o)),o?s:a}function d(t){const e=new Map;for(const r of t){r.children=d(r.children);const t=r.path+"|"+(r.element||"");if(e.has(t)){const n=e.get(t);n.children=d(n.children.concat(r.children)),n.isIndex=n.isIndex||r.isIndex}else e.set(t,{...r})}return Array.from(e.values())}async function p(o){const{sourceDir:a="src/pages",outputDir:s="src/shared/routes",outputName:c="bgs-routes",baseUrl:i="pages",layoutName:u="_layout",authGuardDir:l,notFoundDir:p,errorBoundaryDir:f,minify:$=!0,logging:h=!0}=o||{};try{const o=t.resolve(process.cwd(),a),y=t.resolve(process.cwd(),s,`${c}.tsx`),E=e.readdirSync(o).some((t=>"root.tsx"===t)),g=m(o,o,i,u,p),{imports:w,lazyImports:x,metadataImports:R}=function(t){const e=new Map,r=new Map,n=new Map;return t.forEach((function t(o){o.imports.forEach((t=>{if("layout"===t.type)e.has(t.name)||e.set(t.name,{name:t.name,path:t.path});else if(r.has(t.name)||r.set(t.name,{name:t.name,path:t.path}),t.hasMetadata){const e=`metadata${t.name}`;n.set(t.path,{variableName:e,path:t.path})}})),o.children.forEach(t)})),{imports:Array.from(e.values()),lazyImports:Array.from(r.values()),metadataImports:Array.from(n.values())}}(g),D=[...w.map((t=>`import ${t.name} from "${t.path}";`)),...x.map((t=>`const ${t.name} = lazy(() => import("${t.path}"));`)),...l?[`import AuthGuard from "${l}";`]:[],...E?[`import Root from "${i}/root";`]:[],...f?[`import ErrorBoundary from "${f}";`]:[]].join("\n");let A=n(d(g),R,{sourceDir:a,outputDir:s,outputName:c,baseUrl:i,layoutName:u,minify:$,logging:h,authGuardDir:l,notFoundDir:p});E&&(A=`[{\n element: <Root />,\n ${f?"errorElement: <ErrorBoundary />,":""}\n children: ${A}\n }]`);let I=`\n// @ts-nocheck\nimport { createBrowserRouter } from "react-router-dom";\nimport React, { lazy } from "react";\n\n${D}\n\nexport const routes = ${A};\n\nconst router = createBrowserRouter(routes);\n\nexport default router;\n `.trim();$&&(I=`// @ts-nocheck \n${I.replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"").replace(/[\n\r\t]/g,"").replace(/\s+/g," ")}`);let b=!0;try{await r.readFile(y,"utf-8")===I&&(b=!1)}catch{}b&&(await r.mkdir(t.dirname(y),{recursive:!0}),await r.writeFile(y,I,"utf-8"))}catch(t){}}exports.default=t=>{const e=t?.sourceDir||"src/pages",r=function(){let r;return function(...n){clearTimeout(r),r=setTimeout((()=>{(r=>{r?.replace(/\\/g,"/")?.includes(e)&&p(t)})(...n)}),500)}}();return{name:"bgs-react-router",enforce:"pre",async configResolved(){await p(t)},async buildStart(){await p(t)},transform(t,r){if(r?.replace(/\\/g,"/")?.includes(e)){const n=r.endsWith(".tsx")||r.endsWith(".jsx")?o(r,e):"";return`\n (function() {\n const originalWarn = console.warn;\n console.warn = function(msg, ...args) {\n if (typeof msg === "string" && msg.includes("No \`HydrateFallback\` element")) {\n return;\n }\n originalWarn.apply(console, [msg, ...args]);\n };\n })();\n \n ${t}\n ${n?`window.__METADATA${n} = typeof metadata !== "undefined" ? metadata : {};`:""}\n `}},configureServer(t){r(e),t.watcher.on("add",r).on("change",r).on("unlink",r).on("addDir",r).on("unlinkDir",r)}}};