@eyedea/next-roots
Version:
Utility to handle internationalized routing for Next.js app folder.
146 lines (119 loc) • 18.4 kB
JavaScript
;var Yt=Object.create;var at=Object.defineProperty;var te=Object.getOwnPropertyDescriptor;var ee=Object.getOwnPropertyNames;var re=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var ne=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ee(e))!oe.call(t,n)&&n!==r&&at(t,n,{get:()=>e[n],enumerable:!(o=te(e,n))||o.enumerable});return t};var y=(t,e,r)=>(r=t!=null?Yt(re(t)):{},ne(e||!t||!t.__esModule?at(r,"default",{value:t,enumerable:!0}):r,t));var Qt=y(require("node-watch")),Jt=y(require("parse-typed-args")),M=y(require("path"));function it(...t){return e=>t.map(r=>r(e))}var c=require("fs"),G=y(require("path"));function D(t,e){I(G.default.dirname(t)),(0,c.writeFileSync)(t,e)}function st(t,e="utf8"){return W(t)?(0,c.readFileSync)(t).toString(e):""}function ct(t,e){t!==e&&(I(G.default.dirname(e)),(0,c.copyFileSync)(t,e))}function W(t){return(0,c.existsSync)(t)?(0,c.statSync)(t).isFile():!1}function I(t){(0,c.existsSync)(t)||(0,c.mkdirSync)(t,{recursive:!0})}function b(t){h(t)&&((0,c.readdirSync)(t).forEach(e=>{let r=G.default.join(t,e);h(r)?b(r):(0,c.unlinkSync)(r)}),(0,c.rmdirSync)(t))}function h(t){return(0,c.existsSync)(t)?(0,c.statSync)(t).isDirectory():!1}var yt=require("path-to-regexp");var ft=y(require("path"));function pt(t,e){let r=0;if(t===e)return 0;for(;t[r]===e[r];)r++;return r}var mt=y(require("path"));function gt(t){return t.charAt(0).toUpperCase()+t.slice(1)}function ut(t){return t.replace(/[^a-zA-Z0-9]/gi,"")}function q(t){return t.replace(/\.[^/.]+$/,"")}function lt(t){return t.startsWith("/")?t.slice(1):t}function Z(t){return t=t.replaceAll(mt.default.sep,"/"),t=t.replace(/\/\/+/g,"/"),t=t.replace(/\/$/,""),t}function Q(...t){return t.join("/")}function f(...t){let e=Q(...t);return e=Z(e),e=e.startsWith("/")?e:`/${e}`,e}function S(...t){return e=>t.reduce((r,o)=>o(r),e)}function g(t){return`{{${t}}}`}function u(...t){return t.reduce((e,r)=>({...e,[r]:g(r)}),{})}function P(...t){return(e,r)=>{let n=S(...t.filter(Boolean))(e);return Object.entries(r).reduce((a,[i,s])=>a.replaceAll(g(i),s||""),n)}}function N({getLocalizedAbsolutePath:t,getOriginAbsolutePath:e}){return r=>{let o=e(r.originPath),n=t(r.localizedPath),a=pt(o,n),i=f(o.slice(a)),s=f(n.slice(a)),p=[...ft.default.dirname(s).split("/").slice(1).map(()=>".."),i];return S(Z,q,lt)(Q(...p))}}function $(t="page"){return e=>{let r=S(q,ut,gt);return(e.originPath.match(new RegExp(`^/${t}.([tj])sx?$`))?`root/${t}`:e.originPath).split(/[-/_]/g).map(r).join("")}}var w=class{rewrite;originContents;constructor(e,r){this.rewrite=e,this.originContents=r}getOriginContents(){return this.originContents}getRewrite(){return this.rewrite}};function x(t){return t.replaceAll(/:any\)/g,")")}var L=u("routeLocales","routeNamesStatic","routeNamesDynamic","routeParamsDynamic"),ae=`
export type RouteLocale = ${L.routeLocales};
export type RouteNameStatic = ${L.routeNamesStatic};
export type RouteName = RouteNameStatic;
export type Route = { name: RouteName; href: \`/\${string}\` };
export type RouteParamsStatic<T extends object = object> = T & { locale?: string };
export type RouterSchema = { defaultLocale: string, locales: string[], routes: Record<RouteLocale, Route[]> };
export class Router {
constructor(schema: RouterSchema)
static getPageHref(): string
static setPageHref(pageHref: string): void
getHref<T extends RouteNameStatic>(name: T): string
getHref<T extends RouteNameStatic>(name: T, params: RouteParamsStatic): string
getLocaleFromHref(href: string): string
getRouteFromHref(href: string): Route | undefined
}
export const schema: RouterSchema;
export function compileHref(href: string, params: Record<string, string>): string
export function formatHref(href: string, params: Record<string, string>): string
export type PageProps<TParams = void> = TParams extends void
? { pageHref: string }
: { pageHref: string; params: TParams }
export type LayoutProps<TParams = any> = { locale: string, params: TParams }
export type GeneratePageMetadataProps<TParams = any> = { pageHref: string, params: TParams }
export type GenerateLayoutMetadataProps<TParams = any> = { locale: string, params: TParams }
export type GenerateStaticParamsProps = { pageLocale: string }
`,ie=`
export type RouteLocale = ${L.routeLocales};
export type RouteNameStatic = ${L.routeNamesStatic};
export type RouteNameDynamic = ${L.routeNamesDynamic};
export type RouteName = RouteNameStatic | RouteNameDynamic;
export type Route = { name: RouteName; href: \`/\${string}\` };
export type RouteParamsStatic<T extends object = object> = T & { locale?: string };
export type RouteParamsDynamic<T extends RouteName> = ${L.routeParamsDynamic};
export type RouterSchema = { defaultLocale: string, locales: string[], routes: Record<RouteLocale, Route[]> };
export class Router {
constructor(schema: RouterSchema)
static getPageHref(): string
static setPageHref(pageHref: string): void
getHref<T extends RouteNameDynamic>(name: T, params: RouteParamsDynamic<T>): string
getHref<T extends RouteNameStatic>(name: T): string
getHref<T extends RouteNameStatic>(name: T, params: RouteParamsStatic): string
getLocaleFromHref(href: string): string
getRouteFromHref(href: string): Route | undefined
}
export const schema: RouterSchema;
export function compileHref(href: string, params: Record<string, string>): string
export function formatHref(href: string, params: Record<string, string>): string
export type PageProps<TParams = void> = TParams extends void
? { pageHref: string }
: { pageHref: string; params: TParams }
export type LayoutProps<TParams = any> = { locale: string, params: TParams }
export type GeneratePageMetadataProps<TParams = any> = { pageHref: string, params: TParams }
export type GenerateLayoutMetadataProps<TParams = any> = { locale: string, params: TParams }
export type GenerateStaticParamsProps = { pageLocale: string }
`;function se(t){return e=>!t(e)}function ce(t,e,r){let o=`'${t}'`;return e<r.length-1&&(o+=" | "),o}function J(t){return t.map(ce).join("")}function Pt(t){return t.name}function X(t){return!!t.name.match(/\[\w+\]/g)}function Y(t){return t.routes[t.defaultLocale]||[]}function pe(t){let e=Y(t);return e==null?void 0:e.filter(se(X)).map(Pt)}function me(t){let e=Y(t);return e==null?void 0:e.filter(X).map(Pt)}function ge(t){let e=Y(t);return(e==null?void 0:e.filter(X)).reduce((o,n,a,i)=>{let s=[];return(0,yt.pathToRegexp)(n.href,s),o+=`T extends '${n.name}' ? RouteParamsStatic<{${s.map(m=>`${m.name}:string`)}}> : `,a===i.length-1&&(o+="RouteParamsStatic"),o},"")}function ue(t){return{routeLocales:J(t.locales),routeNamesDynamic:J(me(t)),routeNamesStatic:J(pe(t)),routeParamsDynamic:ge(t)}}function dt(t){let e=ue(t);return P()(e.routeNamesDynamic?ie:ae,e)}function ht({getDistAbsolutePath:t}){return e=>{let r=t("index.d.ts"),o=dt(e);D(r,o)}}function F({defaultLocale:t,locales:e}){return r=>{let o=r.startsWith("/")?r.slice(1):r,[n]=o.split("/");return e.includes(n)?n:t}}function z(t){return!!t.originPath.match(/\[\w+\]/g)}function T(t){return!!t.localizedPath.match(/\.tsx?$/g)}var tt={originPath:g("originPath"),locale:g("locale")},le=`
export { metadata } from '${tt.originPath}'
`,fe=`
import {generateMetadata as generateMetadataOrigin} from '${tt.originPath}'
export async function generateMetadata(props:any) {
return generateMetadataOrigin({ ...props, locale: "${tt.locale}" })
}
`;function ye(t){return`${t}${le}`}function Pe(t){return e=>{let r=`${e}${fe}`;return T(t)||(r=x(r)),r}}function Rt(t){return t.getOriginContents().match(/export async function generateMetadata/g)?Pe(t.getRewrite()):t.getOriginContents().match(/export const metadata/g)?ye:e=>e}var A=u("dynamic","dynamicParams","revalidate","fetchCache","runtime","preferredRegion"),de={dynamic:`export const dynamic = ${A.dynamic}
`,dynamicParams:`export const dynamicParams = ${A.dynamicParams}
`,revalidate:`export const revalidate = ${A.revalidate}
`,fetchCache:`export const fetchCache = ${A.fetchCache}
`,runtime:`export const runtime = ${A.runtime}
`,preferredRegion:`export const preferredRegion = ${A.preferredRegion}
`},he={dynamic:/export const dynamic = (.*)/,dynamicParams:/export const dynamicParams = (.*)/,revalidate:/export const revalidate = (.*)/,fetchCache:/export const fetchCache = (.*)/,runtime:/export const runtime = (.*)/,preferredRegion:/export const preferredRegion = (.*)/};function Re(t){return Object.entries(he).reduce((e,[r,o])=>{var n;return e[r]=(n=t.match(o))==null?void 0:n[1],e},{})}function xe(t,e){return de[t].replace(g(t),e)}function Fe(t){let e=Object.entries(t).reduce((r,[o,n])=>n?`${r}${xe(o,n)}`:r,"");return r=>e===""?r:`${r}
${e}`}function B(t){let e=Re(t.getOriginContents());return Fe(e)}var v=u("originName","originPath","locale"),xt=`
import ${v.originName}Origin from '${v.originPath}'
export default function ${v.originName}(props:any) {
{/* @ts-ignore */}
return <${v.originName}Origin {...props} locale="${v.locale}" />
}
`;function Te(t){return e=>{let r=N(t),o=$("layout"),n=F({defaultLocale:t.defaultLocale,locales:t.locales});return{originPath:r(e),originName:o(e),locale:n(e.localizedPath)}}}function Ft(t){let e=Te(t);return r=>{let o=e(r),n=T(r)?xt:x(xt),a=t.getOriginContents(r.originPath),i=new w(r,a);return P(B(i),Rt(i))(n,o)}}var H=u("originName","originPath","locale"),Se=`
import ${H.originName}Origin from '${H.originPath}'
export default function ${H.originName}() {
{/* @ts-ignore */}
return <${H.originName}Origin locale="${H.locale}" />
}
`;function Ce(t){return e=>{let r=N(t),o=$("not-found"),n=F({defaultLocale:t.defaultLocale,locales:t.locales});return{originPath:r(e),originName:o(e),locale:n(e.localizedPath)}}}function Tt(t){let e=Ce(t);return r=>{let o=e(r);return P()(Se,o)}}var E=class extends Error{},O=class extends E{},_=class extends E{};function De(t){var r;let e=(r=t.match(/\/[(\w-)]+/))==null?void 0:r[0];return(e==null?void 0:e.replace(/\/\([\w-]+\)/,""))||""}function we(t){return t.replace(/\/[(\w-)]+/,"")}function St(t){return t.replace(/\/page\.([tj])sx?$/,"")}function Ct(t){return t.replace(/\/\([\w-]+\)/g,"")}function Dt(t){return t.replace(/\/@\w+/g,"")}function wt(t){let e=t.replace(/\(\.\)/g,""),r=/[[\w-\]]+\/\(\.{2}\)/g;for(;r.test(e);)e=e.replace(r,"");return e.replace(/.*\(\.{3}\)/g,"/")}function Ne(t){return t.replace(/\/\[(\w+)\]/g,"/:$1")}function $e({originPath:t}){let e=S(St,Ct,Dt,wt);return f(e(t))}function Le({localizedPath:t}){let e=De(t),r=S(we,St,Ct,Dt,wt,Ne);return f(e,r(t))}function Ae({originPath:t}){return!!t.match(/\/page\.([tj])sx?$/)||t==="/"}function Nt(t){return!!(t&&typeof t=="object"&&"name"in t&&"href"in t)}function U(t){if(Ae(t))return{name:$e(t),href:Le(t)}}var $t={originPath:g("originPath"),pageLocale:g("pageLocale")},Ee=`
import {generateStaticParams as generateStaticParamsOrigin} from '${$t.originPath}'
export async function generateStaticParams() {
return generateStaticParamsOrigin({ pageLocale: "${$t.pageLocale}" })
}
`;function Oe(t){return`${t}${Ee}`}function Lt(t){return t.getOriginContents().match(/export async function generateStaticParams/g)?Oe:e=>e}var j={originPath:g("originPath"),pageHref:g("pageHref")},be=`
export { metadata } from '${j.originPath}'
`,ve=`
import {generateMetadata as generateMetadataOrigin} from '${j.originPath}'
export async function generateMetadata(props:any) {
return generateMetadataOrigin({ ...props, pageHref: "${j.pageHref}" })
}
`,He=`
import {generateMetadata as generateMetadataOrigin} from '${j.originPath}'
export async function generateMetadata({ params, ...otherProps }:any) {
return generateMetadataOrigin({ ...otherProps, params, pageHref: compileHref('${j.pageHref}', params) })
}
`;function je(t){return`${t}${be}`}function Me(t){return e=>{let r=`${e}${z(t)?He:ve}`;return T(t)||(r=x(r)),r}}function At(t){return t.getOriginContents().match(/export async function generateMetadata/g)?Me(t.getRewrite()):t.getOriginContents().match(/export const metadata/g)?je:e=>e}var d=u("originPath","originName","pageHref"),Ge=`
import ${d.originName}Origin from '${d.originPath}'
import { Router } from 'next-roots'
export default function ${d.originName}(props:any) {
Router.setPageHref("${d.pageHref}")
{/* @ts-ignore */}
return <${d.originName}Origin {...props} pageHref={Router.getPageHref()} />
}
`,Ie=`
import ${d.originName}Origin from '${d.originPath}'
import { Router, compileHref } from 'next-roots'
export default function ${d.originName}({ params, ...otherProps }:any) {
Router.setPageHref(compileHref('${d.pageHref}', params))
{/* @ts-ignore */}
return <${d.originName}Origin {...otherProps} params={params} pageHref={Router.getPageHref()} />
}
`;function ze(t){return e=>{let r=U(e);if(!r)throw new _("Given rewrite is not a page route rewrite.");let o=N(t),n=$("page"),a=F({defaultLocale:t.defaultLocale,locales:t.locales});return{originPath:o(e),originName:n(e),pageLocale:a(e.localizedPath),pageHref:r.href}}}function Et(t){let e=ze(t);return r=>{let o=z(r)?Ie:Ge;o=T(r)?o:x(o);let n=e(r),a=t.getOriginContents(r.originPath),i=new w(r,a);return P(At(i),Lt(i),B(i))(o,n)}}function Be(t){return t.match(/page\.([tj]sx)?$/)}function _e(t){return t.match(/layout\.([tj]sx)?$/)}function Ue(t){return t.match(/not-found\.([tj]sx)?$/)}function ke(t){return({originPath:e})=>{if(Be(e))return Et(t);if(_e(e))return Ft(t);if(Ue(e))return Tt(t)}}function Ve(t){return e=>{let{getOriginAbsolutePath:r,getLocalizedAbsolutePath:o}=t,{localizedPath:n,originPath:a}=e,i=r(a),s=o(n),p=ke(t)(e);if(p){let l=p(e);D(s,l)}else ct(i,s)}}function Ot(t){return e=>{let{locales:r,getLocalizedAbsolutePath:o}=t,n=o();b(n);let a=Ve(t);e.map(a)}}var Ke=u("schema"),We=`
module.exports = Object.freeze(${Ke.schema});
`;function qe(t){return{schema:JSON.stringify(t)}}function bt(t){let e=qe(t);return P()(We,e)}function vt({getCacheAbsolutePath:t}){return e=>{let r=t("schema.js"),o=bt(e);D(r,o)}}var It=y(require("fs")),k=y(require("path")),zt=require("url");var Ht=require("crypto"),jt=require("esbuild"),Mt=y(require("path"));async function Gt(t,e){let r=(0,Ht.createHash)("md5").update(t).digest("hex");return(0,jt.build)({entryPoints:[t],outdir:`./${e}`,entryNames:r,bundle:!0,minify:!0,treeShaking:!0,platform:"node",format:"cjs",target:"node14",drop:["debugger"],conditions:["react-server","next-roots-mock"]}).then(()=>Mt.default.resolve(`${e}/${r}.js`))}var Bt=["i18n.ts","i18n.mjs","i18n.js"],_t=".next-roots";async function Ze(t){return import((0,zt.pathToFileURL)(t).toString()).then(r=>r.default?r.default:r)}async function Qe(t){try{if(!W(t))return;t=await Gt(t,_t);let{routeNames:e,generateRouteNames:r}=await Ze(t);return r?await r():e}catch{return}}function Je(t){return Bt.map(e=>k.default.join(t,e))}async function Xe(t){let e=Je(t),r;for(let o of e)r=r||await Qe(o);return r}function Ye(t){let e=r=>Number(h(k.default.join(t,r)));return It.default.readdirSync(t).filter(r=>!Bt.includes(r)).sort((r,o)=>e(o)-e(r))}async function et({dirName:t,locales:e,defaultLocale:r,parentOrigin:o}){let n=Ye(t),a=[];for(let i of n){let s=k.default.join(t,i),m={path:f((o==null?void 0:o.path)||"",i),localizations:e.map(p=>{var l;return{locale:p,path:f(((l=o==null?void 0:o.localizations.find(R=>R.locale===p))==null?void 0:l.path)||"",i)}})};if(h(s)){let p=await Xe(s),l=await et({defaultLocale:r,locales:e,parentOrigin:{...m,localizations:m.localizations.map(R=>{var C;return{...R,path:R.path.replace(i,((C=p==null?void 0:p.find(({locale:ot})=>R.locale===ot))==null?void 0:C.path)||i)}})},dirName:s});a.push(...l)}else a.push(m)}return b(_t),a}function Ut({defaultLocale:t,prefixDefaultLocale:e}){return r=>r.localizations.map(o=>({originPath:r.path,localizedPath:f(!e&&o.locale===t?`(${o.locale})`:o.locale,o.path)}))}function kt({routes:t,locales:e,defaultLocale:r}){let o=F({locales:e,defaultLocale:r}),n={defaultLocale:r,locales:e,routes:{}};return t.forEach(a=>{let i=o(a.href)||r,s=n.routes[i]||[];s.some(({name:p})=>a.name===p)||(n.routes[i]=[...s,a])}),n}function Vt(t){let{defaultLocale:e,locales:r,getOriginAbsolutePath:o}=t,n=Ot(t),a=ht(t),i=vt(t),s=Ut(t);return async()=>{let m="\x1B[32mnext-roots\x1B[37m - generation done in";console.time(m);let p=await et({locales:r,defaultLocale:e,dirName:o()}),l=p.flatMap(s),R=l.flatMap(U).filter(Nt),C=kt({routes:R,defaultLocale:e,locales:r});return it(()=>n(l),()=>a(C),()=>i(C),()=>{var nt;return(nt=t.afterGenerate)==null?void 0:nt.call(t,{config:t,origins:p,rewrites:l,routes:R,routerSchema:C})},()=>console.timeEnd(m))()}}var K=y(require("path"));var Kt="next-roots",Wt="./roots",qt="./app";function V(t){return(e="")=>K.default.join(t,e)}function tr(t){return e=>st(t(e))}function Zt(t){let e=K.default.join(t.packageDir,"dist"),r=V(t.originDir),o=V(t.localizedDir);if(!h(r()))throw new O('Invalid "originDir" path. Directory does not exist.');let n=o();if(h(n)||I(n),!h(o()))throw new O('Invalid "localizedDir" path. Directory neither exists nor be created.');let a=V(e),i=V(K.default.join(e,"cache")),s=t.defaultLocale||t.locales.at(0)||"";if(!t.locales.includes(s))throw new O('Invalid or empty "defaultLocale". Must be one of given "locales".');let m=tr(r);return Object.freeze({locales:t.locales,defaultLocale:s,prefixDefaultLocale:t.prefixDefaultLocale,getLocalizedAbsolutePath:o,getOriginAbsolutePath:r,getDistAbsolutePath:a,getCacheAbsolutePath:i,getOriginContents:m,afterGenerate:t.afterGenerate})}var er=(0,Jt.default)({opts:{cfgPath:{default:"roots.config.js",short:"c",parse:String},watch:{switch:!0,short:"w"}}})(process.argv),{watch:rr,cfgPath:or}=er.opts,nr={localizedDir:M.default.resolve(qt),originDir:M.default.resolve(Wt),defaultLocale:"",locales:[],prefixDefaultLocale:!0,packageDir:M.default.join(process.cwd(),`node_modules/${Kt}`)},ar=require(M.default.join(process.cwd(),or)),ir={...nr,...ar},Xt=Zt(ir);async function sr(){return process.on("SIGTERM",()=>process.exit(0)),process.on("SIGINT",()=>process.exit(0)),Vt(Xt)()}var rt=async()=>sr().catch(t=>{t instanceof E?console.error(`\x1B[31mnext-roots\x1B[37m - ${t.message}`):console.error(t)});if(rr){let t=(0,Qt.default)(Xt.getOriginAbsolutePath(),{recursive:!0});t.on("ready",function(){console.warn("\x1B[33mnext-roots\x1B[37m - running in watch mode"),rt()}),t.on("change",function(){console.warn("\x1B[33mnext-roots\x1B[37m - origins changed, regenerating..."),rt()})}else rt();
//# sourceMappingURL=cli.js.map