UNPKG

@resolid/flex-routes

Version:

React Router flex file-system routes

3 lines 4.13 kB
import{getAppDirectory as e}from"@react-router/dev/routes";import{makeRe as t}from"minimatch";import{extname as n,join as r,relative as i,win32 as a}from"node:path";import{readdir as o}from"node:fs/promises";const s=async(e,t,n=e)=>{for(let a of await o(e,{withFileTypes:!0,encoding:`utf8`})){let o=r(e,a.name);a.isDirectory()?await s(o,t,n):a.isFile()&&t(i(n,o))}},c=e=>{let t=[],n=[],r=0,i=``,a=``,o=`NORMAL`,s=(e,r)=>{if(e){if(r.includes(`*`)||r.includes(`:`)||r.includes(`?`))throw Error("路由文件或目录中不能存在 `*` `:` `?` 特殊字符");t.push(e),n.push(r)}};for(;r<e.length;){let t=e[r];switch(r++,o){case`NORMAL`:if(t&&[`.`,`/`].includes(t)){s(i,a),i=``,a=``,o=`NORMAL`;break}if(t===`[`){o=`ESCAPE`,a+=t;break}if(t===`(`){o=`OPTIONAL`,a+=t;break}if(!i&&t==`$`){r===e.length?(i+=`*`,a+=t):(i+=`:`,a+=t);break}i+=t,a+=t;break;case`ESCAPE`:if(t===`]`){o=`NORMAL`,a+=t;break}i+=t,a+=t;break;case`OPTIONAL`:if(t===`)`){i+=`?`,a+=t,o=`NORMAL`;break}if(t===`[`){o=`OPTIONAL_ESCAPE`,a+=t;break}if(!i&&t===`$`){r===e.length?(i+=`*`,a+=t):(i+=`:`,a+=t);break}i+=t,a+=t;break;case`OPTIONAL_ESCAPE`:if(t===`]`){o=`OPTIONAL`,a+=t;break}i+=t,a+=t;break}}return s(i,a),[t,n]},l=(e,t,n)=>{let r=[],i=n?e.slice(0,-1):e;for(let e=0;e<i.length;e++){let n=t[e],a=i[e];a.startsWith(`_`)&&n.startsWith(`_`)||(a.endsWith(`_`)&&n.endsWith(`_`)&&(a=a.slice(0,-1)),r.push(a))}return r.length?r.join(`/`):void 0},u=Symbol(`PrefixLookupTrieEndSymbol`);var d=class{root={[u]:!1};add(e){if(!e)throw Error(`Cannot add empty string to PrefixLookupTrie`);let t=this.root;for(let n of e)t[n]||(t[n]={[u]:!1}),t=t[n];t[u]=!0}findAndRemove(e,t){let n=this.root;for(let t of e){if(!n[t])return[];n=n[t]}return this.#findAndRemoveRecursive([],n,e,t)}#findAndRemoveRecursive(e,t,n,r){for(let i of Object.keys(t))this.#findAndRemoveRecursive(e,t[i],n+i,r);return t[u]&&r(n)&&(t[u]=!1,e.push(n)),e}};const f=e=>e.split(a.sep).join(`/`),p=(e,t=`root`)=>{let n={};for(let t in e){let r=e[t];n[t]={id:r.id,file:r.file,path:r.path,index:r.index,caseSensitive:r.caseSensitive}}let r=[];for(let i in n){let a=n[i],o=e[a.id].parentId;if(o===t)r.push(a);else{let e=o&&n[o];e&&(e.children=e.children||[],e.children.push(a))}}return r},m=(e,t)=>{let i={},a=new Map,o=new Map;for(let i of t){let t=f(r(e,i)),s=t.slice(0,-n(t).length),c=s.slice(-7)==`_layout`?s.slice(0,-8):s,l=a.get(c);if(l){let e=o.get(c)??[l];e.push(t),o.set(c,e);continue}a.set(c,t)}let s=new d,u=Array.from(a).sort(([e],[t])=>t.length-e.length);for(let[t,n]of u){let[r,a]=c(t.slice(e.length+1)),o=t.slice(-6)==`_index`,u=l(r,a,o);i[t]={file:n,id:t,path:u},o&&(i[t].index=!0);let d=s.findAndRemove(t,e=>[`.`,`/`].includes(e.slice(t.length).charAt(0)));if(s.add(t),d.length>0)for(let e of d)i[e].parentId=t}let p=new Map;for(let[e]of u){let t=i[e];if(!t.parentId)continue;let n=p.get(t.parentId)||[];n.push(t),p.set(t.parentId,n)}let m=new Map,h=new Map;for(let[t]of u){let n=i[t],r=n.path||``,a=n.parentId?i[n.parentId]:null,o=n.path;a?.path&&o&&(o=o.slice(a.path.length).replace(/^\//,``).replace(/\/$/,``)),n.parentId||=`root`,n.path=o||void 0;let s=n.id.replace(RegExp(`^${e}/`),``).split(/[./]/).pop();if(s&&s[0]==`_`&&s!==`_index`)continue;let c=r+(n.index?`?index`:``),l=m.get(c);if(m.set(c,n),l&&(r||n.index)){let e=h.get(r);e||=[l],e.push(n),h.set(r,e)}}if(o.size>0)for(let[e,t]of o.entries()){let[n,...r]=t,i=r.map(e=>`⭕ ${e}`).join(` `);console.error(`!Route ID 冲突: "${e}"\n\n下列路由都定义了相同的路由 ID,但只有第一个会生效\n\n🟢 ${n}\n${i}\n`)}if(h.size>0)for(let[e,t]of h.entries()){for(let e=1;e<t.length;e++)delete i[t[e].id];let[n,...r]=t.map(e=>e.file),a=e[0]==`/`?e:`/${e}`,o=r.map(e=>`⭕ ${e}`).join(` `);console.error(`! Route 路径冲突: "${a}"\n\n下列路由都定义了相同的 URL,但只有第一个会生效\n\n🟢 ${n}\n${o}\n`)}return i},h=[`.js`,`.jsx`,`.ts`,`.tsx`,`.md`,`.mdx`],g=async(i={})=>{let{routesDirectory:a=`routes`,ignoredRouteFiles:o=[]}=i,c=e(),l=o.map(e=>t(e)).filter(e=>!!e),u=[];await s(r(c,a),e=>{l.some(t=>t.test(e))||h.includes(n(e))&&u.push(e)});let d=m(a,u);return p(d)};export{g as flexRoutes};