main repo

This commit is contained in:
Basilosaurusrex
2025-11-24 18:09:40 +01:00
parent b636ee5e70
commit f027651f9b
34146 changed files with 4436636 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
import { addPathPrefix } from "./add-path-prefix";
import { pathHasPrefix } from "./path-has-prefix";
/**
* For a given path and a locale, if the locale is given, it will prefix the
* locale. The path shouldn't be an API path. If a default locale is given the
* prefix will be omitted if the locale is already the default locale.
*/ export function addLocale(path, locale, defaultLocale, ignorePrefix) {
// If no locale was given or the locale is the default locale, we don't need
// to prefix the path.
if (!locale || locale === defaultLocale) return path;
const lower = path.toLowerCase();
// If the path is an API path or the path already has the locale prefix, we
// don't need to prefix the path.
if (!ignorePrefix) {
if (pathHasPrefix(lower, "/api")) return path;
if (pathHasPrefix(lower, "/" + locale.toLowerCase())) return path;
}
// Add the locale prefix to the path.
return addPathPrefix(path, "/" + locale);
}
//# sourceMappingURL=add-locale.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/add-locale.ts"],"names":["addPathPrefix","pathHasPrefix","addLocale","path","locale","defaultLocale","ignorePrefix","lower","toLowerCase"],"mappings":"AAAA,SAASA,aAAa,QAAQ,oBAAmB;AACjD,SAASC,aAAa,QAAQ,oBAAmB;AAEjD;;;;CAIC,GACD,OAAO,SAASC,UACdC,IAAY,EACZC,MAAuB,EACvBC,aAAsB,EACtBC,YAAsB;IAEtB,4EAA4E;IAC5E,sBAAsB;IACtB,IAAI,CAACF,UAAUA,WAAWC,eAAe,OAAOF;IAEhD,MAAMI,QAAQJ,KAAKK,WAAW;IAE9B,2EAA2E;IAC3E,iCAAiC;IACjC,IAAI,CAACF,cAAc;QACjB,IAAIL,cAAcM,OAAO,SAAS,OAAOJ;QACzC,IAAIF,cAAcM,OAAO,AAAC,MAAGH,OAAOI,WAAW,KAAO,OAAOL;IAC/D;IAEA,qCAAqC;IACrC,OAAOH,cAAcG,MAAM,AAAC,MAAGC;AACjC"}

View File

@@ -0,0 +1,13 @@
import { parsePath } from "./parse-path";
/**
* Adds the provided prefix to the given path. It first ensures that the path
* is indeed starting with a slash.
*/ export function addPathPrefix(path, prefix) {
if (!path.startsWith("/") || !prefix) {
return path;
}
const { pathname, query, hash } = parsePath(path);
return "" + prefix + pathname + query + hash;
}
//# sourceMappingURL=add-path-prefix.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/add-path-prefix.ts"],"names":["parsePath","addPathPrefix","path","prefix","startsWith","pathname","query","hash"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAc;AAExC;;;CAGC,GACD,OAAO,SAASC,cAAcC,IAAY,EAAEC,MAAe;IACzD,IAAI,CAACD,KAAKE,UAAU,CAAC,QAAQ,CAACD,QAAQ;QACpC,OAAOD;IACT;IAEA,MAAM,EAAEG,QAAQ,EAAEC,KAAK,EAAEC,IAAI,EAAE,GAAGP,UAAUE;IAC5C,OAAO,AAAC,KAAEC,SAASE,WAAWC,QAAQC;AACxC"}

View File

@@ -0,0 +1,14 @@
import { parsePath } from "./parse-path";
/**
* Similarly to `addPathPrefix`, this function adds a suffix at the end on the
* provided path. It also works only for paths ensuring the argument starts
* with a slash.
*/ export function addPathSuffix(path, suffix) {
if (!path.startsWith("/") || !suffix) {
return path;
}
const { pathname, query, hash } = parsePath(path);
return "" + pathname + suffix + query + hash;
}
//# sourceMappingURL=add-path-suffix.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/add-path-suffix.ts"],"names":["parsePath","addPathSuffix","path","suffix","startsWith","pathname","query","hash"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAc;AAExC;;;;CAIC,GACD,OAAO,SAASC,cAAcC,IAAY,EAAEC,MAAe;IACzD,IAAI,CAACD,KAAKE,UAAU,CAAC,QAAQ,CAACD,QAAQ;QACpC,OAAOD;IACT;IAEA,MAAM,EAAEG,QAAQ,EAAEC,KAAK,EAAEC,IAAI,EAAE,GAAGP,UAAUE;IAC5C,OAAO,AAAC,KAAEG,WAAWF,SAASG,QAAQC;AACxC"}

View File

@@ -0,0 +1,50 @@
import { ensureLeadingSlash } from "../../page-path/ensure-leading-slash";
import { isGroupSegment } from "../../segment";
/**
* Normalizes an app route so it represents the actual request path. Essentially
* performing the following transformations:
*
* - `/(dashboard)/user/[id]/page` to `/user/[id]`
* - `/(dashboard)/account/page` to `/account`
* - `/user/[id]/page` to `/user/[id]`
* - `/account/page` to `/account`
* - `/page` to `/`
* - `/(dashboard)/user/[id]/route` to `/user/[id]`
* - `/(dashboard)/account/route` to `/account`
* - `/user/[id]/route` to `/user/[id]`
* - `/account/route` to `/account`
* - `/route` to `/`
* - `/` to `/`
*
* @param route the app route to normalize
* @returns the normalized pathname
*/ export function normalizeAppPath(route) {
return ensureLeadingSlash(route.split("/").reduce((pathname, segment, index, segments)=>{
// Empty segments are ignored.
if (!segment) {
return pathname;
}
// Groups are ignored.
if (isGroupSegment(segment)) {
return pathname;
}
// Parallel segments are ignored.
if (segment[0] === "@") {
return pathname;
}
// The last segment (if it's a leaf) should be ignored.
if ((segment === "page" || segment === "route") && index === segments.length - 1) {
return pathname;
}
return pathname + "/" + segment;
}, ""));
}
/**
* Strips the `.rsc` extension if it's in the pathname.
* Since this function is used on full urls it checks `?` for searchParams handling.
*/ export function normalizeRscPath(pathname, enabled) {
return enabled ? pathname.replace(/\.rsc($|\?)/, // $1 ensures `?` is preserved
"$1") : pathname;
}
//# sourceMappingURL=app-paths.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/app-paths.ts"],"names":["ensureLeadingSlash","isGroupSegment","normalizeAppPath","route","split","reduce","pathname","segment","index","segments","length","normalizeRscPath","enabled","replace"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,uCAAsC;AACzE,SAASC,cAAc,QAAQ,gBAAe;AAE9C;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASC,iBAAiBC,KAAa;IAC5C,OAAOH,mBACLG,MAAMC,KAAK,CAAC,KAAKC,MAAM,CAAC,CAACC,UAAUC,SAASC,OAAOC;QACjD,8BAA8B;QAC9B,IAAI,CAACF,SAAS;YACZ,OAAOD;QACT;QAEA,sBAAsB;QACtB,IAAIL,eAAeM,UAAU;YAC3B,OAAOD;QACT;QAEA,iCAAiC;QACjC,IAAIC,OAAO,CAAC,EAAE,KAAK,KAAK;YACtB,OAAOD;QACT;QAEA,uDAAuD;QACvD,IACE,AAACC,CAAAA,YAAY,UAAUA,YAAY,OAAM,KACzCC,UAAUC,SAASC,MAAM,GAAG,GAC5B;YACA,OAAOJ;QACT;QAEA,OAAO,AAAGA,WAAS,MAAGC;IACxB,GAAG;AAEP;AAEA;;;CAGC,GACD,OAAO,SAASI,iBAAiBL,QAAgB,EAAEM,OAAiB;IAClE,OAAOA,UACHN,SAASO,OAAO,CACd,eACA,8BAA8B;IAC9B,QAEFP;AACN"}

View File

@@ -0,0 +1,21 @@
import { normalizeRscPath } from "./app-paths";
describe("normalizeRscPath", ()=>{
describe("enabled", ()=>{
it("should normalize url with .rsc", ()=>{
expect(normalizeRscPath("/test.rsc", true)).toBe("/test");
});
it("should normalize url with .rsc and searchparams", ()=>{
expect(normalizeRscPath("/test.rsc?abc=def", true)).toBe("/test?abc=def");
});
});
describe("disabled", ()=>{
it("should normalize url with .rsc", ()=>{
expect(normalizeRscPath("/test.rsc", false)).toBe("/test.rsc");
});
it("should normalize url with .rsc and searchparams", ()=>{
expect(normalizeRscPath("/test.rsc?abc=def", false)).toBe("/test.rsc?abc=def");
});
});
});
//# sourceMappingURL=app-paths.test.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/app-paths.test.ts"],"names":["normalizeRscPath","describe","it","expect","toBe"],"mappings":"AAAA,SAASA,gBAAgB,QAAQ,cAAa;AAE9CC,SAAS,oBAAoB;IAC3BA,SAAS,WAAW;QAClBC,GAAG,kCAAkC;YACnCC,OAAOH,iBAAiB,aAAa,OAAOI,IAAI,CAAC;QACnD;QACAF,GAAG,mDAAmD;YACpDC,OAAOH,iBAAiB,qBAAqB,OAAOI,IAAI,CAAC;QAC3D;IACF;IACAH,SAAS,YAAY;QACnBC,GAAG,kCAAkC;YACnCC,OAAOH,iBAAiB,aAAa,QAAQI,IAAI,CAAC;QACpD;QACAF,GAAG,mDAAmD;YACpDC,OAAOH,iBAAiB,qBAAqB,QAAQI,IAAI,CACvD;QAEJ;IACF;AACF"}

View File

@@ -0,0 +1,7 @@
// Convert router.asPath to a URLSearchParams object
// example: /dynamic/[slug]?foo=bar -> { foo: 'bar' }
export function asPathToSearchParams(asPath) {
return new URL(asPath, "http://n").searchParams;
}
//# sourceMappingURL=as-path-to-search-params.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/as-path-to-search-params.ts"],"names":["asPathToSearchParams","asPath","URL","searchParams"],"mappings":"AAAA,oDAAoD;AACpD,qDAAqD;AACrD,OAAO,SAASA,qBAAqBC,MAAc;IACjD,OAAO,IAAIC,IAAID,QAAQ,YAAYE,YAAY;AACjD"}

View File

@@ -0,0 +1,24 @@
export function compareRouterStates(a, b) {
const stateKeys = Object.keys(a);
if (stateKeys.length !== Object.keys(b).length) return false;
for(let i = stateKeys.length; i--;){
const key = stateKeys[i];
if (key === "query") {
const queryKeys = Object.keys(a.query);
if (queryKeys.length !== Object.keys(b.query).length) {
return false;
}
for(let j = queryKeys.length; j--;){
const queryKey = queryKeys[j];
if (!b.query.hasOwnProperty(queryKey) || a.query[queryKey] !== b.query[queryKey]) {
return false;
}
}
} else if (!b.hasOwnProperty(key) || a[key] !== b[key]) {
return false;
}
}
return true;
}
//# sourceMappingURL=compare-states.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/compare-states.ts"],"names":["compareRouterStates","a","b","stateKeys","Object","keys","length","i","key","queryKeys","query","j","queryKey","hasOwnProperty"],"mappings":"AAEA,OAAO,SAASA,oBAAoBC,CAAkB,EAAEC,CAAkB;IACxE,MAAMC,YAAYC,OAAOC,IAAI,CAACJ;IAC9B,IAAIE,UAAUG,MAAM,KAAKF,OAAOC,IAAI,CAACH,GAAGI,MAAM,EAAE,OAAO;IAEvD,IAAK,IAAIC,IAAIJ,UAAUG,MAAM,EAAEC,KAAO;QACpC,MAAMC,MAAML,SAAS,CAACI,EAAE;QACxB,IAAIC,QAAQ,SAAS;YACnB,MAAMC,YAAYL,OAAOC,IAAI,CAACJ,EAAES,KAAK;YACrC,IAAID,UAAUH,MAAM,KAAKF,OAAOC,IAAI,CAACH,EAAEQ,KAAK,EAAEJ,MAAM,EAAE;gBACpD,OAAO;YACT;YACA,IAAK,IAAIK,IAAIF,UAAUH,MAAM,EAAEK,KAAO;gBACpC,MAAMC,WAAWH,SAAS,CAACE,EAAE;gBAC7B,IACE,CAACT,EAAEQ,KAAK,CAACG,cAAc,CAACD,aACxBX,EAAES,KAAK,CAACE,SAAS,KAAKV,EAAEQ,KAAK,CAACE,SAAS,EACvC;oBACA,OAAO;gBACT;YACF;QACF,OAAO,IACL,CAACV,EAAEW,cAAc,CAACL,QAClBP,CAAC,CAACO,IAA6B,KAAKN,CAAC,CAACM,IAA6B,EACnE;YACA,OAAO;QACT;IACF;IAEA,OAAO;AACT"}

View File

@@ -0,0 +1,6 @@
// escape delimiters used by path-to-regexp
export default function escapePathDelimiters(segment, escapeEncoded) {
return segment.replace(new RegExp("([/#?]" + (escapeEncoded ? "|%(2f|23|3f)" : "") + ")", "gi"), (char)=>encodeURIComponent(char));
}
//# sourceMappingURL=escape-path-delimiters.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/escape-path-delimiters.ts"],"names":["escapePathDelimiters","segment","escapeEncoded","replace","RegExp","char","encodeURIComponent"],"mappings":"AAAA,2CAA2C;AAC3C,eAAe,SAASA,qBACtBC,OAAe,EACfC,aAAuB;IAEvB,OAAOD,QAAQE,OAAO,CACpB,IAAIC,OAAO,AAAC,WAAQF,CAAAA,gBAAgB,iBAAiB,EAAC,IAAE,KAAI,OAC5D,CAACG,OAAiBC,mBAAmBD;AAEzC"}

View File

@@ -0,0 +1,17 @@
import { removeTrailingSlash } from "./remove-trailing-slash";
import { addPathPrefix } from "./add-path-prefix";
import { addPathSuffix } from "./add-path-suffix";
import { addLocale } from "./add-locale";
export function formatNextPathnameInfo(info) {
let pathname = addLocale(info.pathname, info.locale, info.buildId ? undefined : info.defaultLocale, info.ignorePrefix);
if (info.buildId || !info.trailingSlash) {
pathname = removeTrailingSlash(pathname);
}
if (info.buildId) {
pathname = addPathSuffix(addPathPrefix(pathname, "/_next/data/" + info.buildId), info.pathname === "/" ? "index.json" : ".json");
}
pathname = addPathPrefix(pathname, info.basePath);
return !info.buildId && info.trailingSlash ? !pathname.endsWith("/") ? addPathSuffix(pathname, "/") : pathname : removeTrailingSlash(pathname);
}
//# sourceMappingURL=format-next-pathname-info.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/format-next-pathname-info.ts"],"names":["removeTrailingSlash","addPathPrefix","addPathSuffix","addLocale","formatNextPathnameInfo","info","pathname","locale","buildId","undefined","defaultLocale","ignorePrefix","trailingSlash","basePath","endsWith"],"mappings":"AACA,SAASA,mBAAmB,QAAQ,0BAAyB;AAC7D,SAASC,aAAa,QAAQ,oBAAmB;AACjD,SAASC,aAAa,QAAQ,oBAAmB;AACjD,SAASC,SAAS,QAAQ,eAAc;AAOxC,OAAO,SAASC,uBAAuBC,IAAkB;IACvD,IAAIC,WAAWH,UACbE,KAAKC,QAAQ,EACbD,KAAKE,MAAM,EACXF,KAAKG,OAAO,GAAGC,YAAYJ,KAAKK,aAAa,EAC7CL,KAAKM,YAAY;IAGnB,IAAIN,KAAKG,OAAO,IAAI,CAACH,KAAKO,aAAa,EAAE;QACvCN,WAAWN,oBAAoBM;IACjC;IAEA,IAAID,KAAKG,OAAO,EAAE;QAChBF,WAAWJ,cACTD,cAAcK,UAAU,AAAC,iBAAcD,KAAKG,OAAO,GACnDH,KAAKC,QAAQ,KAAK,MAAM,eAAe;IAE3C;IAEAA,WAAWL,cAAcK,UAAUD,KAAKQ,QAAQ;IAChD,OAAO,CAACR,KAAKG,OAAO,IAAIH,KAAKO,aAAa,GACtC,CAACN,SAASQ,QAAQ,CAAC,OACjBZ,cAAcI,UAAU,OACxBA,WACFN,oBAAoBM;AAC1B"}

View File

@@ -0,0 +1,84 @@
// Format function modified from nodejs
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import * as querystring from "./querystring";
const slashedProtocols = /https?|ftp|gopher|file/;
export function formatUrl(urlObj) {
let { auth, hostname } = urlObj;
let protocol = urlObj.protocol || "";
let pathname = urlObj.pathname || "";
let hash = urlObj.hash || "";
let query = urlObj.query || "";
let host = false;
auth = auth ? encodeURIComponent(auth).replace(/%3A/i, ":") + "@" : "";
if (urlObj.host) {
host = auth + urlObj.host;
} else if (hostname) {
host = auth + (~hostname.indexOf(":") ? "[" + hostname + "]" : hostname);
if (urlObj.port) {
host += ":" + urlObj.port;
}
}
if (query && typeof query === "object") {
query = String(querystring.urlQueryToSearchParams(query));
}
let search = urlObj.search || query && "?" + query || "";
if (protocol && !protocol.endsWith(":")) protocol += ":";
if (urlObj.slashes || (!protocol || slashedProtocols.test(protocol)) && host !== false) {
host = "//" + (host || "");
if (pathname && pathname[0] !== "/") pathname = "/" + pathname;
} else if (!host) {
host = "";
}
if (hash && hash[0] !== "#") hash = "#" + hash;
if (search && search[0] !== "?") search = "?" + search;
pathname = pathname.replace(/[?#]/g, encodeURIComponent);
search = search.replace("#", "%23");
return "" + protocol + host + pathname + search + hash;
}
export const urlObjectKeys = [
"auth",
"hash",
"host",
"hostname",
"href",
"path",
"pathname",
"port",
"protocol",
"query",
"search",
"slashes"
];
export function formatWithValidation(url) {
if (process.env.NODE_ENV === "development") {
if (url !== null && typeof url === "object") {
Object.keys(url).forEach((key)=>{
if (!urlObjectKeys.includes(key)) {
console.warn("Unknown key passed via urlObject into url.format: " + key);
}
});
}
}
return formatUrl(url);
}
//# sourceMappingURL=format-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/format-url.ts"],"names":["querystring","slashedProtocols","formatUrl","urlObj","auth","hostname","protocol","pathname","hash","query","host","encodeURIComponent","replace","indexOf","port","String","urlQueryToSearchParams","search","endsWith","slashes","test","urlObjectKeys","formatWithValidation","url","process","env","NODE_ENV","Object","keys","forEach","key","includes","console","warn"],"mappings":"AAAA,uCAAuC;AACvC,sDAAsD;AACtD,EAAE;AACF,0EAA0E;AAC1E,gEAAgE;AAChE,sEAAsE;AACtE,sEAAsE;AACtE,4EAA4E;AAC5E,qEAAqE;AACrE,wBAAwB;AACxB,EAAE;AACF,0EAA0E;AAC1E,yDAAyD;AACzD,EAAE;AACF,0EAA0E;AAC1E,6DAA6D;AAC7D,4EAA4E;AAC5E,2EAA2E;AAC3E,wEAAwE;AACxE,4EAA4E;AAC5E,yCAAyC;AAIzC,YAAYA,iBAAiB,gBAAe;AAE5C,MAAMC,mBAAmB;AAEzB,OAAO,SAASC,UAAUC,MAAiB;IACzC,IAAI,EAAEC,IAAI,EAAEC,QAAQ,EAAE,GAAGF;IACzB,IAAIG,WAAWH,OAAOG,QAAQ,IAAI;IAClC,IAAIC,WAAWJ,OAAOI,QAAQ,IAAI;IAClC,IAAIC,OAAOL,OAAOK,IAAI,IAAI;IAC1B,IAAIC,QAAQN,OAAOM,KAAK,IAAI;IAC5B,IAAIC,OAAuB;IAE3BN,OAAOA,OAAOO,mBAAmBP,MAAMQ,OAAO,CAAC,QAAQ,OAAO,MAAM;IAEpE,IAAIT,OAAOO,IAAI,EAAE;QACfA,OAAON,OAAOD,OAAOO,IAAI;IAC3B,OAAO,IAAIL,UAAU;QACnBK,OAAON,OAAQ,CAAA,CAACC,SAASQ,OAAO,CAAC,OAAO,AAAC,MAAGR,WAAS,MAAKA,QAAO;QACjE,IAAIF,OAAOW,IAAI,EAAE;YACfJ,QAAQ,MAAMP,OAAOW,IAAI;QAC3B;IACF;IAEA,IAAIL,SAAS,OAAOA,UAAU,UAAU;QACtCA,QAAQM,OAAOf,YAAYgB,sBAAsB,CAACP;IACpD;IAEA,IAAIQ,SAASd,OAAOc,MAAM,IAAKR,SAAS,AAAC,MAAGA,SAAY;IAExD,IAAIH,YAAY,CAACA,SAASY,QAAQ,CAAC,MAAMZ,YAAY;IAErD,IACEH,OAAOgB,OAAO,IACb,AAAC,CAAA,CAACb,YAAYL,iBAAiBmB,IAAI,CAACd,SAAQ,KAAMI,SAAS,OAC5D;QACAA,OAAO,OAAQA,CAAAA,QAAQ,EAAC;QACxB,IAAIH,YAAYA,QAAQ,CAAC,EAAE,KAAK,KAAKA,WAAW,MAAMA;IACxD,OAAO,IAAI,CAACG,MAAM;QAChBA,OAAO;IACT;IAEA,IAAIF,QAAQA,IAAI,CAAC,EAAE,KAAK,KAAKA,OAAO,MAAMA;IAC1C,IAAIS,UAAUA,MAAM,CAAC,EAAE,KAAK,KAAKA,SAAS,MAAMA;IAEhDV,WAAWA,SAASK,OAAO,CAAC,SAASD;IACrCM,SAASA,OAAOL,OAAO,CAAC,KAAK;IAE7B,OAAO,AAAC,KAAEN,WAAWI,OAAOH,WAAWU,SAAST;AAClD;AAEA,OAAO,MAAMa,gBAAgB;IAC3B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAA;AAED,OAAO,SAASC,qBAAqBC,GAAc;IACjD,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,eAAe;QAC1C,IAAIH,QAAQ,QAAQ,OAAOA,QAAQ,UAAU;YAC3CI,OAAOC,IAAI,CAACL,KAAKM,OAAO,CAAC,CAACC;gBACxB,IAAI,CAACT,cAAcU,QAAQ,CAACD,MAAM;oBAChCE,QAAQC,IAAI,CACV,AAAC,uDAAoDH;gBAEzD;YACF;QACF;IACF;IAEA,OAAO5B,UAAUqB;AACnB"}

View File

@@ -0,0 +1,9 @@
// Translates a logical route into its pages asset path (relative from a common prefix)
// "asset path" being its javascript file, data file, prerendered html,...
export default function getAssetPathFromRoute(route, ext) {
if (ext === void 0) ext = "";
const path = route === "/" ? "/index" : /^\/index(\/|$)/.test(route) ? "/index" + route : "" + route;
return path + ext;
}
//# sourceMappingURL=get-asset-path-from-route.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/get-asset-path-from-route.ts"],"names":["getAssetPathFromRoute","route","ext","path","test"],"mappings":"AAAA,uFAAuF;AACvF,0EAA0E;AAC1E,eAAe,SAASA,sBACtBC,KAAa,EACbC,GAAgB;IAAhBA,IAAAA,gBAAAA,MAAc;IAEd,MAAMC,OACJF,UAAU,MACN,WACA,iBAAiBG,IAAI,CAACH,SACtB,AAAC,WAAQA,QACT,AAAC,KAAEA;IACT,OAAOE,OAAOD;AAChB"}

View File

@@ -0,0 +1,44 @@
import { normalizeLocalePath } from "../../i18n/normalize-locale-path";
import { removePathPrefix } from "./remove-path-prefix";
import { pathHasPrefix } from "./path-has-prefix";
export function getNextPathnameInfo(pathname, options) {
var _options_nextConfig;
const { basePath, i18n, trailingSlash } = (_options_nextConfig = options.nextConfig) != null ? _options_nextConfig : {};
const info = {
pathname,
trailingSlash: pathname !== "/" ? pathname.endsWith("/") : trailingSlash
};
if (basePath && pathHasPrefix(info.pathname, basePath)) {
info.pathname = removePathPrefix(info.pathname, basePath);
info.basePath = basePath;
}
let pathnameNoDataPrefix = info.pathname;
if (info.pathname.startsWith("/_next/data/") && info.pathname.endsWith(".json")) {
const paths = info.pathname.replace(/^\/_next\/data\//, "").replace(/\.json$/, "").split("/");
const buildId = paths[0];
info.buildId = buildId;
pathnameNoDataPrefix = paths[1] !== "index" ? "/" + paths.slice(1).join("/") : "/";
// update pathname with normalized if enabled although
// we use normalized to populate locale info still
if (options.parseData === true) {
info.pathname = pathnameNoDataPrefix;
}
}
// If provided, use the locale route normalizer to detect the locale instead
// of the function below.
if (i18n) {
let result = options.i18nProvider ? options.i18nProvider.analyze(info.pathname) : normalizeLocalePath(info.pathname, i18n.locales);
info.locale = result.detectedLocale;
var _result_pathname;
info.pathname = (_result_pathname = result.pathname) != null ? _result_pathname : info.pathname;
if (!result.detectedLocale && info.buildId) {
result = options.i18nProvider ? options.i18nProvider.analyze(pathnameNoDataPrefix) : normalizeLocalePath(pathnameNoDataPrefix, i18n.locales);
if (result.detectedLocale) {
info.locale = result.detectedLocale;
}
}
}
return info;
}
//# sourceMappingURL=get-next-pathname-info.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/get-next-pathname-info.ts"],"names":["normalizeLocalePath","removePathPrefix","pathHasPrefix","getNextPathnameInfo","pathname","options","basePath","i18n","trailingSlash","nextConfig","info","endsWith","pathnameNoDataPrefix","startsWith","paths","replace","split","buildId","slice","join","parseData","result","i18nProvider","analyze","locales","locale","detectedLocale"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,mCAAkC;AACtE,SAASC,gBAAgB,QAAQ,uBAAsB;AACvD,SAASC,aAAa,QAAQ,oBAAmB;AAkDjD,OAAO,SAASC,oBACdC,QAAgB,EAChBC,OAAgB;QAE0BA;IAA1C,MAAM,EAAEC,QAAQ,EAAEC,IAAI,EAAEC,aAAa,EAAE,GAAGH,CAAAA,sBAAAA,QAAQI,UAAU,YAAlBJ,sBAAsB,CAAC;IACjE,MAAMK,OAAyB;QAC7BN;QACAI,eAAeJ,aAAa,MAAMA,SAASO,QAAQ,CAAC,OAAOH;IAC7D;IAEA,IAAIF,YAAYJ,cAAcQ,KAAKN,QAAQ,EAAEE,WAAW;QACtDI,KAAKN,QAAQ,GAAGH,iBAAiBS,KAAKN,QAAQ,EAAEE;QAChDI,KAAKJ,QAAQ,GAAGA;IAClB;IACA,IAAIM,uBAAuBF,KAAKN,QAAQ;IAExC,IACEM,KAAKN,QAAQ,CAACS,UAAU,CAAC,mBACzBH,KAAKN,QAAQ,CAACO,QAAQ,CAAC,UACvB;QACA,MAAMG,QAAQJ,KAAKN,QAAQ,CACxBW,OAAO,CAAC,oBAAoB,IAC5BA,OAAO,CAAC,WAAW,IACnBC,KAAK,CAAC;QAET,MAAMC,UAAUH,KAAK,CAAC,EAAE;QACxBJ,KAAKO,OAAO,GAAGA;QACfL,uBACEE,KAAK,CAAC,EAAE,KAAK,UAAU,AAAC,MAAGA,MAAMI,KAAK,CAAC,GAAGC,IAAI,CAAC,OAAS;QAE1D,sDAAsD;QACtD,kDAAkD;QAClD,IAAId,QAAQe,SAAS,KAAK,MAAM;YAC9BV,KAAKN,QAAQ,GAAGQ;QAClB;IACF;IAEA,4EAA4E;IAC5E,yBAAyB;IACzB,IAAIL,MAAM;QACR,IAAIc,SAAShB,QAAQiB,YAAY,GAC7BjB,QAAQiB,YAAY,CAACC,OAAO,CAACb,KAAKN,QAAQ,IAC1CJ,oBAAoBU,KAAKN,QAAQ,EAAEG,KAAKiB,OAAO;QAEnDd,KAAKe,MAAM,GAAGJ,OAAOK,cAAc;YACnBL;QAAhBX,KAAKN,QAAQ,GAAGiB,CAAAA,mBAAAA,OAAOjB,QAAQ,YAAfiB,mBAAmBX,KAAKN,QAAQ;QAEhD,IAAI,CAACiB,OAAOK,cAAc,IAAIhB,KAAKO,OAAO,EAAE;YAC1CI,SAAShB,QAAQiB,YAAY,GACzBjB,QAAQiB,YAAY,CAACC,OAAO,CAACX,wBAC7BZ,oBAAoBY,sBAAsBL,KAAKiB,OAAO;YAE1D,IAAIH,OAAOK,cAAc,EAAE;gBACzBhB,KAAKe,MAAM,GAAGJ,OAAOK,cAAc;YACrC;QACF;IACF;IACA,OAAOhB;AACT"}

View File

@@ -0,0 +1,16 @@
// Translate a pages asset path (relative from a common prefix) back into its logical route
import { isDynamicRoute } from "./is-dynamic";
// "asset path" being its javascript file, data file, prerendered html,...
export default function getRouteFromAssetPath(assetPath, ext) {
if (ext === void 0) ext = "";
assetPath = assetPath.replace(/\\/g, "/");
assetPath = ext && assetPath.endsWith(ext) ? assetPath.slice(0, -ext.length) : assetPath;
if (assetPath.startsWith("/index/") && !isDynamicRoute(assetPath)) {
assetPath = assetPath.slice(6);
} else if (assetPath === "/index") {
assetPath = "/";
}
return assetPath;
}
//# sourceMappingURL=get-route-from-asset-path.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/get-route-from-asset-path.ts"],"names":["isDynamicRoute","getRouteFromAssetPath","assetPath","ext","replace","endsWith","slice","length","startsWith"],"mappings":"AAAA,2FAA2F;AAE3F,SAASA,cAAc,QAAQ,eAAc;AAE7C,0EAA0E;AAC1E,eAAe,SAASC,sBACtBC,SAAiB,EACjBC,GAAgB;IAAhBA,IAAAA,gBAAAA,MAAc;IAEdD,YAAYA,UAAUE,OAAO,CAAC,OAAO;IACrCF,YACEC,OAAOD,UAAUG,QAAQ,CAACF,OAAOD,UAAUI,KAAK,CAAC,GAAG,CAACH,IAAII,MAAM,IAAIL;IACrE,IAAIA,UAAUM,UAAU,CAAC,cAAc,CAACR,eAAeE,YAAY;QACjEA,YAAYA,UAAUI,KAAK,CAAC;IAC9B,OAAO,IAAIJ,cAAc,UAAU;QACjCA,YAAY;IACd;IACA,OAAOA;AACT"}

View File

@@ -0,0 +1,25 @@
/**
* Run function with `scroll-behavior: auto` applied to `<html/>`.
* This css change will be reverted after the function finishes.
*/ export function handleSmoothScroll(fn, options) {
if (options === void 0) options = {};
// if only the hash is changed, we don't need to disable smooth scrolling
// we only care to prevent smooth scrolling when navigating to a new page to avoid jarring UX
if (options.onlyHashChange) {
fn();
return;
}
const htmlElement = document.documentElement;
const existing = htmlElement.style.scrollBehavior;
htmlElement.style.scrollBehavior = "auto";
if (!options.dontForceLayout) {
// In Chrome-based browsers we need to force reflow before calling `scrollTo`.
// Otherwise it will not pickup the change in scrollBehavior
// More info here: https://github.com/vercel/next.js/issues/40719#issuecomment-1336248042
htmlElement.getClientRects();
}
fn();
htmlElement.style.scrollBehavior = existing;
}
//# sourceMappingURL=handle-smooth-scroll.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/handle-smooth-scroll.ts"],"names":["handleSmoothScroll","fn","options","onlyHashChange","htmlElement","document","documentElement","existing","style","scrollBehavior","dontForceLayout","getClientRects"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,mBACdC,EAAc,EACdC,OAAqE;IAArEA,IAAAA,oBAAAA,UAAmE,CAAC;IAEpE,yEAAyE;IACzE,6FAA6F;IAC7F,IAAIA,QAAQC,cAAc,EAAE;QAC1BF;QACA;IACF;IACA,MAAMG,cAAcC,SAASC,eAAe;IAC5C,MAAMC,WAAWH,YAAYI,KAAK,CAACC,cAAc;IACjDL,YAAYI,KAAK,CAACC,cAAc,GAAG;IACnC,IAAI,CAACP,QAAQQ,eAAe,EAAE;QAC5B,8EAA8E;QAC9E,4DAA4D;QAC5D,yFAAyF;QACzFN,YAAYO,cAAc;IAC5B;IACAV;IACAG,YAAYI,KAAK,CAACC,cAAc,GAAGF;AACrC"}

View File

@@ -0,0 +1,4 @@
export { getSortedRoutes } from "./sorted-routes";
export { isDynamicRoute } from "./is-dynamic";
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/index.ts"],"names":["getSortedRoutes","isDynamicRoute"],"mappings":"AAAA,SAASA,eAAe,QAAQ,kBAAiB;AACjD,SAASC,cAAc,QAAQ,eAAc"}

View File

@@ -0,0 +1,43 @@
import { getRouteMatcher } from "./route-matcher";
import { getRouteRegex } from "./route-regex";
export function interpolateAs(route, asPathname, query) {
let interpolatedRoute = "";
const dynamicRegex = getRouteRegex(route);
const dynamicGroups = dynamicRegex.groups;
const dynamicMatches = // Try to match the dynamic route against the asPath
(asPathname !== route ? getRouteMatcher(dynamicRegex)(asPathname) : "") || // Fall back to reading the values from the href
// TODO: should this take priority; also need to change in the router.
query;
interpolatedRoute = route;
const params = Object.keys(dynamicGroups);
if (!params.every((param)=>{
let value = dynamicMatches[param] || "";
const { repeat, optional } = dynamicGroups[param];
// support single-level catch-all
// TODO: more robust handling for user-error (passing `/`)
let replaced = "[" + (repeat ? "..." : "") + param + "]";
if (optional) {
replaced = (!value ? "/" : "") + "[" + replaced + "]";
}
if (repeat && !Array.isArray(value)) value = [
value
];
return (optional || param in dynamicMatches) && // Interpolate group into data URL if present
(interpolatedRoute = interpolatedRoute.replace(replaced, repeat ? value.map(// these values should be fully encoded instead of just
// path delimiter escaped since they are being inserted
// into the URL and we expect URL encoded segments
// when parsing dynamic route params
(segment)=>encodeURIComponent(segment)).join("/") : encodeURIComponent(value)) || "/");
})) {
interpolatedRoute = "" // did not satisfy all requirements
;
// n.b. We ignore this error because we handle warning for this case in
// development in the `<Link>` component directly.
}
return {
params,
result: interpolatedRoute
};
}
//# sourceMappingURL=interpolate-as.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/interpolate-as.ts"],"names":["getRouteMatcher","getRouteRegex","interpolateAs","route","asPathname","query","interpolatedRoute","dynamicRegex","dynamicGroups","groups","dynamicMatches","params","Object","keys","every","param","value","repeat","optional","replaced","Array","isArray","replace","map","segment","encodeURIComponent","join","result"],"mappings":"AAEA,SAASA,eAAe,QAAQ,kBAAiB;AACjD,SAASC,aAAa,QAAQ,gBAAe;AAE7C,OAAO,SAASC,cACdC,KAAa,EACbC,UAAkB,EAClBC,KAAqB;IAErB,IAAIC,oBAAoB;IAExB,MAAMC,eAAeN,cAAcE;IACnC,MAAMK,gBAAgBD,aAAaE,MAAM;IACzC,MAAMC,iBAEJ,AADA,oDAAoD;IACnDN,CAAAA,eAAeD,QAAQH,gBAAgBO,cAAcH,cAAc,EAAC,KACrE,gDAAgD;IAChD,sEAAsE;IACtEC;IAEFC,oBAAoBH;IACpB,MAAMQ,SAASC,OAAOC,IAAI,CAACL;IAE3B,IACE,CAACG,OAAOG,KAAK,CAAC,CAACC;QACb,IAAIC,QAAQN,cAAc,CAACK,MAAM,IAAI;QACrC,MAAM,EAAEE,MAAM,EAAEC,QAAQ,EAAE,GAAGV,aAAa,CAACO,MAAM;QAEjD,iCAAiC;QACjC,0DAA0D;QAC1D,IAAII,WAAW,AAAC,MAAGF,CAAAA,SAAS,QAAQ,EAAC,IAAIF,QAAM;QAC/C,IAAIG,UAAU;YACZC,WAAW,AAAG,CAAA,CAACH,QAAQ,MAAM,EAAC,IAAE,MAAGG,WAAS;QAC9C;QACA,IAAIF,UAAU,CAACG,MAAMC,OAAO,CAACL,QAAQA,QAAQ;YAACA;SAAM;QAEpD,OACE,AAACE,CAAAA,YAAYH,SAASL,cAAa,KACnC,6CAA6C;QAC5CJ,CAAAA,oBACCA,kBAAmBgB,OAAO,CACxBH,UACAF,SACI,AAACD,MACEO,GAAG,CACF,uDAAuD;QACvD,uDAAuD;QACvD,kDAAkD;QAClD,oCAAoC;QACpC,CAACC,UAAYC,mBAAmBD,UAEjCE,IAAI,CAAC,OACRD,mBAAmBT,WACpB,GAAE;IAEb,IACA;QACAV,oBAAoB,GAAG,mCAAmC;;IAE1D,uEAAuE;IACvE,kDAAkD;IACpD;IACA,OAAO;QACLK;QACAgB,QAAQrB;IACV;AACF"}

View File

@@ -0,0 +1,5 @@
export function isBot(userAgent) {
return /Googlebot|Mediapartners-Google|AdsBot-Google|googleweblight|Storebot-Google|Google-PageRenderer|Bingbot|BingPreview|Slurp|DuckDuckBot|baiduspider|yandex|sogou|LinkedInBot|bitlybot|tumblr|vkShare|quora link preview|facebookexternalhit|facebookcatalog|Twitterbot|applebot|redditbot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|ia_archiver/i.test(userAgent);
}
//# sourceMappingURL=is-bot.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/is-bot.ts"],"names":["isBot","userAgent","test"],"mappings":"AAAA,OAAO,SAASA,MAAMC,SAAiB;IACrC,OAAO,oVAAoVC,IAAI,CAC7VD;AAEJ"}

View File

@@ -0,0 +1,7 @@
// Identify /[param]/ in route string
const TEST_ROUTE = /\/\[[^/]+?\](?=\/|$)/;
export function isDynamicRoute(route) {
return TEST_ROUTE.test(route);
}
//# sourceMappingURL=is-dynamic.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/is-dynamic.ts"],"names":["TEST_ROUTE","isDynamicRoute","route","test"],"mappings":"AAAA,qCAAqC;AACrC,MAAMA,aAAa;AAEnB,OAAO,SAASC,eAAeC,KAAa;IAC1C,OAAOF,WAAWG,IAAI,CAACD;AACzB"}

View File

@@ -0,0 +1,18 @@
import { isAbsoluteUrl, getLocationOrigin } from "../../utils";
import { hasBasePath } from "../../../../client/has-base-path";
/**
* Detects whether a given url is routable by the Next.js router (browser only).
*/ export function isLocalURL(url) {
// prevent a hydration mismatch on href for url with anchor refs
if (!isAbsoluteUrl(url)) return true;
try {
// absolute urls can be local if they are on the same origin
const locationOrigin = getLocationOrigin();
const resolved = new URL(url, locationOrigin);
return resolved.origin === locationOrigin && hasBasePath(resolved.pathname);
} catch (_) {
return false;
}
}
//# sourceMappingURL=is-local-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/is-local-url.ts"],"names":["isAbsoluteUrl","getLocationOrigin","hasBasePath","isLocalURL","url","locationOrigin","resolved","URL","origin","pathname","_"],"mappings":"AAAA,SAASA,aAAa,EAAEC,iBAAiB,QAAQ,cAAa;AAC9D,SAASC,WAAW,QAAQ,mCAAkC;AAE9D;;CAEC,GACD,OAAO,SAASC,WAAWC,GAAW;IACpC,gEAAgE;IAChE,IAAI,CAACJ,cAAcI,MAAM,OAAO;IAChC,IAAI;QACF,4DAA4D;QAC5D,MAAMC,iBAAiBJ;QACvB,MAAMK,WAAW,IAAIC,IAAIH,KAAKC;QAC9B,OAAOC,SAASE,MAAM,KAAKH,kBAAkBH,YAAYI,SAASG,QAAQ;IAC5E,EAAE,OAAOC,GAAG;QACV,OAAO;IACT;AACF"}

View File

@@ -0,0 +1,21 @@
import { matchHas } from "./prepare-destination";
export function getMiddlewareRouteMatcher(matchers) {
return (pathname, req, query)=>{
for (const matcher of matchers){
const routeMatch = new RegExp(matcher.regexp).exec(pathname);
if (!routeMatch) {
continue;
}
if (matcher.has || matcher.missing) {
const hasParams = matchHas(req, query, matcher.has, matcher.missing);
if (!hasParams) {
continue;
}
}
return true;
}
return false;
};
}
//# sourceMappingURL=middleware-route-matcher.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/middleware-route-matcher.ts"],"names":["matchHas","getMiddlewareRouteMatcher","matchers","pathname","req","query","matcher","routeMatch","RegExp","regexp","exec","has","missing","hasParams"],"mappings":"AAGA,SAASA,QAAQ,QAAQ,wBAAuB;AAUhD,OAAO,SAASC,0BACdC,QAA6B;IAE7B,OAAO,CACLC,UACAC,KACAC;QAEA,KAAK,MAAMC,WAAWJ,SAAU;YAC9B,MAAMK,aAAa,IAAIC,OAAOF,QAAQG,MAAM,EAAEC,IAAI,CAACP;YACnD,IAAI,CAACI,YAAY;gBACf;YACF;YAEA,IAAID,QAAQK,GAAG,IAAIL,QAAQM,OAAO,EAAE;gBAClC,MAAMC,YAAYb,SAASI,KAAKC,OAAOC,QAAQK,GAAG,EAAEL,QAAQM,OAAO;gBACnE,IAAI,CAACC,WAAW;oBACd;gBACF;YACF;YAEA,OAAO;QACT;QAEA,OAAO;IACT;AACF"}

View File

@@ -0,0 +1,11 @@
export function omit(object, keys) {
const omitted = {};
Object.keys(object).forEach((key)=>{
if (!keys.includes(key)) {
omitted[key] = object[key];
}
});
return omitted;
}
//# sourceMappingURL=omit.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/omit.ts"],"names":["omit","object","keys","omitted","Object","forEach","key","includes"],"mappings":"AAAA,OAAO,SAASA,KACdC,MAAS,EACTC,IAAS;IAET,MAAMC,UAAsC,CAAC;IAC7CC,OAAOF,IAAI,CAACD,QAAQI,OAAO,CAAC,CAACC;QAC3B,IAAI,CAACJ,KAAKK,QAAQ,CAACD,MAAW;YAC5BH,OAAO,CAACG,IAAI,GAAGL,MAAM,CAACK,IAAI;QAC5B;IACF;IACA,OAAOH;AACT"}

View File

@@ -0,0 +1,23 @@
/**
* Given a path this function will find the pathname, query and hash and return
* them. This is useful to parse full paths on the client side.
* @param path A path to parse e.g. /foo/bar?id=1#hash
*/ export function parsePath(path) {
const hashIndex = path.indexOf("#");
const queryIndex = path.indexOf("?");
const hasQuery = queryIndex > -1 && (hashIndex < 0 || queryIndex < hashIndex);
if (hasQuery || hashIndex > -1) {
return {
pathname: path.substring(0, hasQuery ? queryIndex : hashIndex),
query: hasQuery ? path.substring(queryIndex, hashIndex > -1 ? hashIndex : undefined) : "",
hash: hashIndex > -1 ? path.slice(hashIndex) : ""
};
}
return {
pathname: path,
query: "",
hash: ""
};
}
//# sourceMappingURL=parse-path.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/parse-path.ts"],"names":["parsePath","path","hashIndex","indexOf","queryIndex","hasQuery","pathname","substring","query","undefined","hash","slice"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,SAASA,UAAUC,IAAY;IACpC,MAAMC,YAAYD,KAAKE,OAAO,CAAC;IAC/B,MAAMC,aAAaH,KAAKE,OAAO,CAAC;IAChC,MAAME,WAAWD,aAAa,CAAC,KAAMF,CAAAA,YAAY,KAAKE,aAAaF,SAAQ;IAE3E,IAAIG,YAAYH,YAAY,CAAC,GAAG;QAC9B,OAAO;YACLI,UAAUL,KAAKM,SAAS,CAAC,GAAGF,WAAWD,aAAaF;YACpDM,OAAOH,WACHJ,KAAKM,SAAS,CAACH,YAAYF,YAAY,CAAC,IAAIA,YAAYO,aACxD;YACJC,MAAMR,YAAY,CAAC,IAAID,KAAKU,KAAK,CAACT,aAAa;QACjD;IACF;IAEA,OAAO;QAAEI,UAAUL;QAAMO,OAAO;QAAIE,MAAM;IAAG;AAC/C"}

View File

@@ -0,0 +1,24 @@
import { getLocationOrigin } from "../../utils";
import { searchParamsToUrlQuery } from "./querystring";
/**
* Parses path-relative urls (e.g. `/hello/world?foo=bar`). If url isn't path-relative
* (e.g. `./hello`) then at least base must be.
* Absolute urls are rejected with one exception, in the browser, absolute urls that are on
* the current origin will be parsed as relative
*/ export function parseRelativeUrl(url, base) {
const globalBase = new URL(typeof window === "undefined" ? "http://n" : getLocationOrigin());
const resolvedBase = base ? new URL(base, globalBase) : url.startsWith(".") ? new URL(typeof window === "undefined" ? "http://n" : window.location.href) : globalBase;
const { pathname, searchParams, search, hash, href, origin } = new URL(url, resolvedBase);
if (origin !== globalBase.origin) {
throw new Error("invariant: invalid relative URL, router received " + url);
}
return {
pathname,
query: searchParamsToUrlQuery(searchParams),
search,
hash,
href: href.slice(globalBase.origin.length)
};
}
//# sourceMappingURL=parse-relative-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/parse-relative-url.ts"],"names":["getLocationOrigin","searchParamsToUrlQuery","parseRelativeUrl","url","base","globalBase","URL","window","resolvedBase","startsWith","location","href","pathname","searchParams","search","hash","origin","Error","query","slice","length"],"mappings":"AACA,SAASA,iBAAiB,QAAQ,cAAa;AAC/C,SAASC,sBAAsB,QAAQ,gBAAe;AAUtD;;;;;CAKC,GACD,OAAO,SAASC,iBACdC,GAAW,EACXC,IAAa;IAEb,MAAMC,aAAa,IAAIC,IACrB,OAAOC,WAAW,cAAc,aAAaP;IAG/C,MAAMQ,eAAeJ,OACjB,IAAIE,IAAIF,MAAMC,cACdF,IAAIM,UAAU,CAAC,OACf,IAAIH,IAAI,OAAOC,WAAW,cAAc,aAAaA,OAAOG,QAAQ,CAACC,IAAI,IACzEN;IAEJ,MAAM,EAAEO,QAAQ,EAAEC,YAAY,EAAEC,MAAM,EAAEC,IAAI,EAAEJ,IAAI,EAAEK,MAAM,EAAE,GAAG,IAAIV,IACjEH,KACAK;IAEF,IAAIQ,WAAWX,WAAWW,MAAM,EAAE;QAChC,MAAM,IAAIC,MAAM,AAAC,sDAAmDd;IACtE;IACA,OAAO;QACLS;QACAM,OAAOjB,uBAAuBY;QAC9BC;QACAC;QACAJ,MAAMA,KAAKQ,KAAK,CAACd,WAAWW,MAAM,CAACI,MAAM;IAC3C;AACF"}

View File

@@ -0,0 +1,20 @@
import { searchParamsToUrlQuery } from "./querystring";
import { parseRelativeUrl } from "./parse-relative-url";
export function parseUrl(url) {
if (url.startsWith("/")) {
return parseRelativeUrl(url);
}
const parsedURL = new URL(url);
return {
hash: parsedURL.hash,
hostname: parsedURL.hostname,
href: parsedURL.href,
pathname: parsedURL.pathname,
port: parsedURL.port,
protocol: parsedURL.protocol,
query: searchParamsToUrlQuery(parsedURL.searchParams),
search: parsedURL.search
};
}
//# sourceMappingURL=parse-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/parse-url.ts"],"names":["searchParamsToUrlQuery","parseRelativeUrl","parseUrl","url","startsWith","parsedURL","URL","hash","hostname","href","pathname","port","protocol","query","searchParams","search"],"mappings":"AAEA,SAASA,sBAAsB,QAAQ,gBAAe;AACtD,SAASC,gBAAgB,QAAQ,uBAAsB;AAavD,OAAO,SAASC,SAASC,GAAW;IAClC,IAAIA,IAAIC,UAAU,CAAC,MAAM;QACvB,OAAOH,iBAAiBE;IAC1B;IAEA,MAAME,YAAY,IAAIC,IAAIH;IAC1B,OAAO;QACLI,MAAMF,UAAUE,IAAI;QACpBC,UAAUH,UAAUG,QAAQ;QAC5BC,MAAMJ,UAAUI,IAAI;QACpBC,UAAUL,UAAUK,QAAQ;QAC5BC,MAAMN,UAAUM,IAAI;QACpBC,UAAUP,UAAUO,QAAQ;QAC5BC,OAAOb,uBAAuBK,UAAUS,YAAY;QACpDC,QAAQV,UAAUU,MAAM;IAC1B;AACF"}

View File

@@ -0,0 +1,16 @@
import { parsePath } from "./parse-path";
/**
* Checks if a given path starts with a given prefix. It ensures it matches
* exactly without containing extra chars. e.g. prefix /docs should replace
* for /docs, /docs/, /docs/a but not /docsss
* @param path The path to check.
* @param prefix The prefix to check against.
*/ export function pathHasPrefix(path, prefix) {
if (typeof path !== "string") {
return false;
}
const { pathname } = parsePath(path);
return pathname === prefix || pathname.startsWith(prefix + "/");
}
//# sourceMappingURL=path-has-prefix.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/path-has-prefix.ts"],"names":["parsePath","pathHasPrefix","path","prefix","pathname","startsWith"],"mappings":"AAAA,SAASA,SAAS,QAAQ,eAAc;AAExC;;;;;;CAMC,GACD,OAAO,SAASC,cAAcC,IAAY,EAAEC,MAAc;IACxD,IAAI,OAAOD,SAAS,UAAU;QAC5B,OAAO;IACT;IAEA,MAAM,EAAEE,QAAQ,EAAE,GAAGJ,UAAUE;IAC/B,OAAOE,aAAaD,UAAUC,SAASC,UAAU,CAACF,SAAS;AAC7D"}

View File

@@ -0,0 +1,44 @@
import { pathToRegexp } from "next/dist/compiled/path-to-regexp";
import { regexpToFunction } from "next/dist/compiled/path-to-regexp";
/**
* Generates a path matcher function for a given path and options based on
* path-to-regexp. By default the match will be case insensitive, non strict
* and delimited by `/`.
*/ export function getPathMatch(path, options) {
const keys = [];
const regexp = pathToRegexp(path, keys, {
delimiter: "/",
sensitive: typeof (options == null ? void 0 : options.sensitive) === "boolean" ? options.sensitive : false,
strict: options == null ? void 0 : options.strict
});
const matcher = regexpToFunction((options == null ? void 0 : options.regexModifier) ? new RegExp(options.regexModifier(regexp.source), regexp.flags) : regexp, keys);
/**
* A matcher function that will check if a given pathname matches the path
* given in the builder function. When the path does not match it will return
* `false` but if it does it will return an object with the matched params
* merged with the params provided in the second argument.
*/ return (pathname, params)=>{
// If no pathname is provided it's not a match.
if (typeof pathname !== "string") return false;
const match = matcher(pathname);
// If the path did not match `false` will be returned.
if (!match) return false;
/**
* If unnamed params are not allowed they must be removed from
* the matched parameters. path-to-regexp uses "string" for named and
* "number" for unnamed parameters.
*/ if (options == null ? void 0 : options.removeUnnamedParams) {
for (const key of keys){
if (typeof key.name === "number") {
delete match.params[key.name];
}
}
}
return {
...params,
...match.params
};
};
}
//# sourceMappingURL=path-match.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/path-match.ts"],"names":["pathToRegexp","regexpToFunction","getPathMatch","path","options","keys","regexp","delimiter","sensitive","strict","matcher","regexModifier","RegExp","source","flags","pathname","params","match","removeUnnamedParams","key","name"],"mappings":"AACA,SAASA,YAAY,QAAQ,oCAAmC;AAChE,SAASC,gBAAgB,QAAQ,oCAAmC;AA8BpE;;;;CAIC,GACD,OAAO,SAASC,aAAaC,IAAY,EAAEC,OAAiB;IAC1D,MAAMC,OAAc,EAAE;IACtB,MAAMC,SAASN,aAAaG,MAAME,MAAM;QACtCE,WAAW;QACXC,WACE,QAAOJ,2BAAAA,QAASI,SAAS,MAAK,YAAYJ,QAAQI,SAAS,GAAG;QAChEC,MAAM,EAAEL,2BAAAA,QAASK,MAAM;IACzB;IAEA,MAAMC,UAAUT,iBACdG,CAAAA,2BAAAA,QAASO,aAAa,IAClB,IAAIC,OAAOR,QAAQO,aAAa,CAACL,OAAOO,MAAM,GAAGP,OAAOQ,KAAK,IAC7DR,QACJD;IAGF;;;;;GAKC,GACD,OAAO,CAACU,UAAUC;QAChB,+CAA+C;QAC/C,IAAI,OAAOD,aAAa,UAAU,OAAO;QAEzC,MAAME,QAAQP,QAAQK;QAEtB,sDAAsD;QACtD,IAAI,CAACE,OAAO,OAAO;QAEnB;;;;KAIC,GACD,IAAIb,2BAAAA,QAASc,mBAAmB,EAAE;YAChC,KAAK,MAAMC,OAAOd,KAAM;gBACtB,IAAI,OAAOc,IAAIC,IAAI,KAAK,UAAU;oBAChC,OAAOH,MAAMD,MAAM,CAACG,IAAIC,IAAI,CAAC;gBAC/B;YACF;QACF;QAEA,OAAO;YAAE,GAAGJ,MAAM;YAAE,GAAGC,MAAMD,MAAM;QAAC;IACtC;AACF"}

View File

@@ -0,0 +1,210 @@
import { compile, pathToRegexp } from "next/dist/compiled/path-to-regexp";
import { escapeStringRegexp } from "../../escape-regexp";
import { parseUrl } from "./parse-url";
import { INTERCEPTION_ROUTE_MARKERS, isInterceptionRouteAppPath } from "../../../../server/future/helpers/interception-routes";
import { NEXT_RSC_UNION_QUERY } from "../../../../client/components/app-router-headers";
import { getCookieParser } from "../../../../server/api-utils/get-cookie-parser";
/**
* Ensure only a-zA-Z are used for param names for proper interpolating
* with path-to-regexp
*/ function getSafeParamName(paramName) {
let newParamName = "";
for(let i = 0; i < paramName.length; i++){
const charCode = paramName.charCodeAt(i);
if (charCode > 64 && charCode < 91 || // A-Z
charCode > 96 && charCode < 123 // a-z
) {
newParamName += paramName[i];
}
}
return newParamName;
}
function escapeSegment(str, segmentName) {
return str.replace(new RegExp(":" + escapeStringRegexp(segmentName), "g"), "__ESC_COLON_" + segmentName);
}
function unescapeSegments(str) {
return str.replace(/__ESC_COLON_/gi, ":");
}
export function matchHas(req, query, has, missing) {
if (has === void 0) has = [];
if (missing === void 0) missing = [];
const params = {};
const hasMatch = (hasItem)=>{
let value;
let key = hasItem.key;
switch(hasItem.type){
case "header":
{
key = key.toLowerCase();
value = req.headers[key];
break;
}
case "cookie":
{
if ("cookies" in req) {
value = req.cookies[hasItem.key];
} else {
const cookies = getCookieParser(req.headers)();
value = cookies[hasItem.key];
}
break;
}
case "query":
{
value = query[key];
break;
}
case "host":
{
const { host } = (req == null ? void 0 : req.headers) || {};
// remove port from host if present
const hostname = host == null ? void 0 : host.split(":")[0].toLowerCase();
value = hostname;
break;
}
default:
{
break;
}
}
if (!hasItem.value && value) {
params[getSafeParamName(key)] = value;
return true;
} else if (value) {
const matcher = new RegExp("^" + hasItem.value + "$");
const matches = Array.isArray(value) ? value.slice(-1)[0].match(matcher) : value.match(matcher);
if (matches) {
if (Array.isArray(matches)) {
if (matches.groups) {
Object.keys(matches.groups).forEach((groupKey)=>{
params[groupKey] = matches.groups[groupKey];
});
} else if (hasItem.type === "host" && matches[0]) {
params.host = matches[0];
}
}
return true;
}
}
return false;
};
const allMatch = has.every((item)=>hasMatch(item)) && !missing.some((item)=>hasMatch(item));
if (allMatch) {
return params;
}
return false;
}
export function compileNonPath(value, params) {
if (!value.includes(":")) {
return value;
}
for (const key of Object.keys(params)){
if (value.includes(":" + key)) {
value = value.replace(new RegExp(":" + key + "\\*", "g"), ":" + key + "--ESCAPED_PARAM_ASTERISKS").replace(new RegExp(":" + key + "\\?", "g"), ":" + key + "--ESCAPED_PARAM_QUESTION").replace(new RegExp(":" + key + "\\+", "g"), ":" + key + "--ESCAPED_PARAM_PLUS").replace(new RegExp(":" + key + "(?!\\w)", "g"), "--ESCAPED_PARAM_COLON" + key);
}
}
value = value.replace(/(:|\*|\?|\+|\(|\)|\{|\})/g, "\\$1").replace(/--ESCAPED_PARAM_PLUS/g, "+").replace(/--ESCAPED_PARAM_COLON/g, ":").replace(/--ESCAPED_PARAM_QUESTION/g, "?").replace(/--ESCAPED_PARAM_ASTERISKS/g, "*");
// the value needs to start with a forward-slash to be compiled
// correctly
return compile("/" + value, {
validate: false
})(params).slice(1);
}
export function prepareDestination(args) {
const query = Object.assign({}, args.query);
delete query.__nextLocale;
delete query.__nextDefaultLocale;
delete query.__nextDataReq;
delete query.__nextInferredLocaleFromDefault;
delete query[NEXT_RSC_UNION_QUERY];
let escapedDestination = args.destination;
for (const param of Object.keys({
...args.params,
...query
})){
escapedDestination = escapeSegment(escapedDestination, param);
}
const parsedDestination = parseUrl(escapedDestination);
const destQuery = parsedDestination.query;
const destPath = unescapeSegments("" + parsedDestination.pathname + (parsedDestination.hash || ""));
const destHostname = unescapeSegments(parsedDestination.hostname || "");
const destPathParamKeys = [];
const destHostnameParamKeys = [];
pathToRegexp(destPath, destPathParamKeys);
pathToRegexp(destHostname, destHostnameParamKeys);
const destParams = [];
destPathParamKeys.forEach((key)=>destParams.push(key.name));
destHostnameParamKeys.forEach((key)=>destParams.push(key.name));
const destPathCompiler = compile(destPath, // we don't validate while compiling the destination since we should
// have already validated before we got to this point and validating
// breaks compiling destinations with named pattern params from the source
// e.g. /something:hello(.*) -> /another/:hello is broken with validation
// since compile validation is meant for reversing and not for inserting
// params from a separate path-regex into another
{
validate: false
});
const destHostnameCompiler = compile(destHostname, {
validate: false
});
// update any params in query values
for (const [key, strOrArray] of Object.entries(destQuery)){
// the value needs to start with a forward-slash to be compiled
// correctly
if (Array.isArray(strOrArray)) {
destQuery[key] = strOrArray.map((value)=>compileNonPath(unescapeSegments(value), args.params));
} else if (typeof strOrArray === "string") {
destQuery[key] = compileNonPath(unescapeSegments(strOrArray), args.params);
}
}
// add path params to query if it's not a redirect and not
// already defined in destination query or path
let paramKeys = Object.keys(args.params).filter((name)=>name !== "nextInternalLocale");
if (args.appendParamsToQuery && !paramKeys.some((key)=>destParams.includes(key))) {
for (const key of paramKeys){
if (!(key in destQuery)) {
destQuery[key] = args.params[key];
}
}
}
let newUrl;
// The compiler also that the interception route marker is an unnamed param, hence '0',
// so we need to add it to the params object.
if (isInterceptionRouteAppPath(destPath)) {
for (const segment of destPath.split("/")){
const marker = INTERCEPTION_ROUTE_MARKERS.find((m)=>segment.startsWith(m));
if (marker) {
args.params["0"] = marker;
break;
}
}
}
try {
newUrl = destPathCompiler(args.params);
const [pathname, hash] = newUrl.split("#");
parsedDestination.hostname = destHostnameCompiler(args.params);
parsedDestination.pathname = pathname;
parsedDestination.hash = "" + (hash ? "#" : "") + (hash || "");
delete parsedDestination.search;
} catch (err) {
if (err.message.match(/Expected .*? to not repeat, but got an array/)) {
throw new Error("To use a multi-match in the destination you must add `*` at the end of the param name to signify it should repeat. https://nextjs.org/docs/messages/invalid-multi-match");
}
throw err;
}
// Query merge order lowest priority to highest
// 1. initial URL query values
// 2. path segment values
// 3. destination specified query values
parsedDestination.query = {
...query,
...parsedDestination.query
};
return {
newUrl,
destQuery,
parsedDestination
};
}
//# sourceMappingURL=prepare-destination.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
export function searchParamsToUrlQuery(searchParams) {
const query = {};
searchParams.forEach((value, key)=>{
if (typeof query[key] === "undefined") {
query[key] = value;
} else if (Array.isArray(query[key])) {
query[key].push(value);
} else {
query[key] = [
query[key],
value
];
}
});
return query;
}
function stringifyUrlQueryParam(param) {
if (typeof param === "string" || typeof param === "number" && !isNaN(param) || typeof param === "boolean") {
return String(param);
} else {
return "";
}
}
export function urlQueryToSearchParams(urlQuery) {
const result = new URLSearchParams();
Object.entries(urlQuery).forEach((param)=>{
let [key, value] = param;
if (Array.isArray(value)) {
value.forEach((item)=>result.append(key, stringifyUrlQueryParam(item)));
} else {
result.set(key, stringifyUrlQueryParam(value));
}
});
return result;
}
export function assign(target) {
for(var _len = arguments.length, searchParamsList = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){
searchParamsList[_key - 1] = arguments[_key];
}
searchParamsList.forEach((searchParams)=>{
Array.from(searchParams.keys()).forEach((key)=>target.delete(key));
searchParams.forEach((value, key)=>target.append(key, value));
});
return target;
}
//# sourceMappingURL=querystring.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/querystring.ts"],"names":["searchParamsToUrlQuery","searchParams","query","forEach","value","key","Array","isArray","push","stringifyUrlQueryParam","param","isNaN","String","urlQueryToSearchParams","urlQuery","result","URLSearchParams","Object","entries","item","append","set","assign","target","searchParamsList","from","keys","delete"],"mappings":"AAEA,OAAO,SAASA,uBACdC,YAA6B;IAE7B,MAAMC,QAAwB,CAAC;IAC/BD,aAAaE,OAAO,CAAC,CAACC,OAAOC;QAC3B,IAAI,OAAOH,KAAK,CAACG,IAAI,KAAK,aAAa;YACrCH,KAAK,CAACG,IAAI,GAAGD;QACf,OAAO,IAAIE,MAAMC,OAAO,CAACL,KAAK,CAACG,IAAI,GAAG;YAClCH,KAAK,CAACG,IAAI,CAAcG,IAAI,CAACJ;QACjC,OAAO;YACLF,KAAK,CAACG,IAAI,GAAG;gBAACH,KAAK,CAACG,IAAI;gBAAYD;aAAM;QAC5C;IACF;IACA,OAAOF;AACT;AAEA,SAASO,uBAAuBC,KAAc;IAC5C,IACE,OAAOA,UAAU,YAChB,OAAOA,UAAU,YAAY,CAACC,MAAMD,UACrC,OAAOA,UAAU,WACjB;QACA,OAAOE,OAAOF;IAChB,OAAO;QACL,OAAO;IACT;AACF;AAEA,OAAO,SAASG,uBACdC,QAAwB;IAExB,MAAMC,SAAS,IAAIC;IACnBC,OAAOC,OAAO,CAACJ,UAAUX,OAAO,CAAC;YAAC,CAACE,KAAKD,MAAM;QAC5C,IAAIE,MAAMC,OAAO,CAACH,QAAQ;YACxBA,MAAMD,OAAO,CAAC,CAACgB,OAASJ,OAAOK,MAAM,CAACf,KAAKI,uBAAuBU;QACpE,OAAO;YACLJ,OAAOM,GAAG,CAAChB,KAAKI,uBAAuBL;QACzC;IACF;IACA,OAAOW;AACT;AAEA,OAAO,SAASO,OACdC,MAAuB;IACvB,IAAA,IAAA,OAAA,UAAA,QAAA,AAAGC,mBAAH,UAAA,OAAA,IAAA,OAAA,QAAA,OAAA,GAAA,OAAA,MAAA,OAAA;QAAGA,iBAAH,OAAA,KAAA,SAAA,CAAA,KAAsC;IAAD;IAErCA,iBAAiBrB,OAAO,CAAC,CAACF;QACxBK,MAAMmB,IAAI,CAACxB,aAAayB,IAAI,IAAIvB,OAAO,CAAC,CAACE,MAAQkB,OAAOI,MAAM,CAACtB;QAC/DJ,aAAaE,OAAO,CAAC,CAACC,OAAOC,MAAQkB,OAAOH,MAAM,CAACf,KAAKD;IAC1D;IACA,OAAOmB;AACT"}

View File

@@ -0,0 +1,12 @@
/**
* Given a URL as a string and a base URL it will make the URL relative
* if the parsed protocol and host is the same as the one in the base
* URL. Otherwise it returns the same URL string.
*/ export function relativizeURL(url, base) {
const baseURL = typeof base === "string" ? new URL(base) : base;
const relative = new URL(url, base);
const origin = baseURL.protocol + "//" + baseURL.host;
return relative.protocol + "//" + relative.host === origin ? relative.toString().replace(origin, "") : relative.toString();
}
//# sourceMappingURL=relativize-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/relativize-url.ts"],"names":["relativizeURL","url","base","baseURL","URL","relative","origin","protocol","host","toString","replace"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,SAASA,cAAcC,GAAoB,EAAEC,IAAkB;IACpE,MAAMC,UAAU,OAAOD,SAAS,WAAW,IAAIE,IAAIF,QAAQA;IAC3D,MAAMG,WAAW,IAAID,IAAIH,KAAKC;IAC9B,MAAMI,SAAS,AAAGH,QAAQI,QAAQ,GAAC,OAAIJ,QAAQK,IAAI;IACnD,OAAO,AAAGH,SAASE,QAAQ,GAAC,OAAIF,SAASG,IAAI,KAAOF,SAChDD,SAASI,QAAQ,GAAGC,OAAO,CAACJ,QAAQ,MACpCD,SAASI,QAAQ;AACvB"}

View File

@@ -0,0 +1,36 @@
import { pathHasPrefix } from "./path-has-prefix";
/**
* Given a path and a prefix it will remove the prefix when it exists in the
* given path. It ensures it matches exactly without containing extra chars
* and if the prefix is not there it will be noop.
*
* @param path The path to remove the prefix from.
* @param prefix The prefix to be removed.
*/ export function removePathPrefix(path, prefix) {
// If the path doesn't start with the prefix we can return it as is. This
// protects us from situations where the prefix is a substring of the path
// prefix such as:
//
// For prefix: /blog
//
// /blog -> true
// /blog/ -> true
// /blog/1 -> true
// /blogging -> false
// /blogging/ -> false
// /blogging/1 -> false
if (!pathHasPrefix(path, prefix)) {
return path;
}
// Remove the prefix from the path via slicing.
const withoutPrefix = path.slice(prefix.length);
// If the path without the prefix starts with a `/` we can return it as is.
if (withoutPrefix.startsWith("/")) {
return withoutPrefix;
}
// If the path without the prefix doesn't start with a `/` we need to add it
// back to the path to make sure it's a valid path.
return "/" + withoutPrefix;
}
//# sourceMappingURL=remove-path-prefix.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/remove-path-prefix.ts"],"names":["pathHasPrefix","removePathPrefix","path","prefix","withoutPrefix","slice","length","startsWith"],"mappings":"AAAA,SAASA,aAAa,QAAQ,oBAAmB;AAEjD;;;;;;;CAOC,GACD,OAAO,SAASC,iBAAiBC,IAAY,EAAEC,MAAc;IAC3D,yEAAyE;IACzE,0EAA0E;IAC1E,kBAAkB;IAClB,EAAE;IACF,oBAAoB;IACpB,EAAE;IACF,kBAAkB;IAClB,mBAAmB;IACnB,oBAAoB;IACpB,uBAAuB;IACvB,wBAAwB;IACxB,yBAAyB;IACzB,IAAI,CAACH,cAAcE,MAAMC,SAAS;QAChC,OAAOD;IACT;IAEA,+CAA+C;IAC/C,MAAME,gBAAgBF,KAAKG,KAAK,CAACF,OAAOG,MAAM;IAE9C,2EAA2E;IAC3E,IAAIF,cAAcG,UAAU,CAAC,MAAM;QACjC,OAAOH;IACT;IAEA,4EAA4E;IAC5E,mDAAmD;IACnD,OAAO,AAAC,MAAGA;AACb"}

View File

@@ -0,0 +1,11 @@
/**
* Removes the trailing slash for a given route or page path. Preserves the
* root page. Examples:
* - `/foo/bar/` -> `/foo/bar`
* - `/foo/bar` -> `/foo/bar`
* - `/` -> `/`
*/ export function removeTrailingSlash(route) {
return route.replace(/\/$/, "") || "/";
}
//# sourceMappingURL=remove-trailing-slash.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/remove-trailing-slash.ts"],"names":["removeTrailingSlash","route","replace"],"mappings":"AAAA;;;;;;CAMC,GACD,OAAO,SAASA,oBAAoBC,KAAa;IAC/C,OAAOA,MAAMC,OAAO,CAAC,OAAO,OAAO;AACrC"}

View File

@@ -0,0 +1,108 @@
import { getPathMatch } from "./path-match";
import { matchHas, prepareDestination } from "./prepare-destination";
import { removeTrailingSlash } from "./remove-trailing-slash";
import { normalizeLocalePath } from "../../i18n/normalize-locale-path";
import { removeBasePath } from "../../../../client/remove-base-path";
import { parseRelativeUrl } from "./parse-relative-url";
export default function resolveRewrites(asPath, pages, rewrites, query, resolveHref, locales) {
let matchedPage = false;
let externalDest = false;
let parsedAs = parseRelativeUrl(asPath);
let fsPathname = removeTrailingSlash(normalizeLocalePath(removeBasePath(parsedAs.pathname), locales).pathname);
let resolvedHref;
const handleRewrite = (rewrite)=>{
const matcher = getPathMatch(rewrite.source + (process.env.__NEXT_TRAILING_SLASH ? "(/)?" : ""), {
removeUnnamedParams: true,
strict: true
});
let params = matcher(parsedAs.pathname);
if ((rewrite.has || rewrite.missing) && params) {
const hasParams = matchHas({
headers: {
host: document.location.hostname,
"user-agent": navigator.userAgent
},
cookies: document.cookie.split("; ").reduce((acc, item)=>{
const [key, ...value] = item.split("=");
acc[key] = value.join("=");
return acc;
}, {})
}, parsedAs.query, rewrite.has, rewrite.missing);
if (hasParams) {
Object.assign(params, hasParams);
} else {
params = false;
}
}
if (params) {
if (!rewrite.destination) {
// this is a proxied rewrite which isn't handled on the client
externalDest = true;
return true;
}
const destRes = prepareDestination({
appendParamsToQuery: true,
destination: rewrite.destination,
params: params,
query: query
});
parsedAs = destRes.parsedDestination;
asPath = destRes.newUrl;
Object.assign(query, destRes.parsedDestination.query);
fsPathname = removeTrailingSlash(normalizeLocalePath(removeBasePath(asPath), locales).pathname);
if (pages.includes(fsPathname)) {
// check if we now match a page as this means we are done
// resolving the rewrites
matchedPage = true;
resolvedHref = fsPathname;
return true;
}
// check if we match a dynamic-route, if so we break the rewrites chain
resolvedHref = resolveHref(fsPathname);
if (resolvedHref !== asPath && pages.includes(resolvedHref)) {
matchedPage = true;
return true;
}
}
};
let finished = false;
for(let i = 0; i < rewrites.beforeFiles.length; i++){
// we don't end after match in beforeFiles to allow
// continuing through all beforeFiles rewrites
handleRewrite(rewrites.beforeFiles[i]);
}
matchedPage = pages.includes(fsPathname);
if (!matchedPage) {
if (!finished) {
for(let i = 0; i < rewrites.afterFiles.length; i++){
if (handleRewrite(rewrites.afterFiles[i])) {
finished = true;
break;
}
}
}
// check dynamic route before processing fallback rewrites
if (!finished) {
resolvedHref = resolveHref(fsPathname);
matchedPage = pages.includes(resolvedHref);
finished = matchedPage;
}
if (!finished) {
for(let i = 0; i < rewrites.fallback.length; i++){
if (handleRewrite(rewrites.fallback[i])) {
finished = true;
break;
}
}
}
}
return {
asPath,
parsedAs,
matchedPage,
resolvedHref,
externalDest
};
}
//# sourceMappingURL=resolve-rewrites.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/resolve-rewrites.ts"],"names":["getPathMatch","matchHas","prepareDestination","removeTrailingSlash","normalizeLocalePath","removeBasePath","parseRelativeUrl","resolveRewrites","asPath","pages","rewrites","query","resolveHref","locales","matchedPage","externalDest","parsedAs","fsPathname","pathname","resolvedHref","handleRewrite","rewrite","matcher","source","process","env","__NEXT_TRAILING_SLASH","removeUnnamedParams","strict","params","has","missing","hasParams","headers","host","document","location","hostname","navigator","userAgent","cookies","cookie","split","reduce","acc","item","key","value","join","Object","assign","destination","destRes","appendParamsToQuery","parsedDestination","newUrl","includes","finished","i","beforeFiles","length","afterFiles","fallback"],"mappings":"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"}

View File

@@ -0,0 +1,30 @@
import { DecodeError } from "../../utils";
export function getRouteMatcher(param) {
let { re, groups } = param;
return (pathname)=>{
const routeMatch = re.exec(pathname);
if (!routeMatch) {
return false;
}
const decode = (param)=>{
try {
return decodeURIComponent(param);
} catch (_) {
throw new DecodeError("failed to decode param");
}
};
const params = {};
Object.keys(groups).forEach((slugName)=>{
const g = groups[slugName];
const m = routeMatch[g.pos];
if (m !== undefined) {
params[slugName] = ~m.indexOf("/") ? m.split("/").map((entry)=>decode(entry)) : g.repeat ? [
decode(m)
] : decode(m);
}
});
return params;
};
}
//# sourceMappingURL=route-matcher.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/route-matcher.ts"],"names":["DecodeError","getRouteMatcher","re","groups","pathname","routeMatch","exec","decode","param","decodeURIComponent","_","params","Object","keys","forEach","slugName","g","m","pos","undefined","indexOf","split","map","entry","repeat"],"mappings":"AACA,SAASA,WAAW,QAAQ,cAAa;AAUzC,OAAO,SAASC,gBAAgB,KAA0B;IAA1B,IAAA,EAAEC,EAAE,EAAEC,MAAM,EAAc,GAA1B;IAC9B,OAAO,CAACC;QACN,MAAMC,aAAaH,GAAGI,IAAI,CAACF;QAC3B,IAAI,CAACC,YAAY;YACf,OAAO;QACT;QAEA,MAAME,SAAS,CAACC;YACd,IAAI;gBACF,OAAOC,mBAAmBD;YAC5B,EAAE,OAAOE,GAAG;gBACV,MAAM,IAAIV,YAAY;YACxB;QACF;QACA,MAAMW,SAAqD,CAAC;QAE5DC,OAAOC,IAAI,CAACV,QAAQW,OAAO,CAAC,CAACC;YAC3B,MAAMC,IAAIb,MAAM,CAACY,SAAS;YAC1B,MAAME,IAAIZ,UAAU,CAACW,EAAEE,GAAG,CAAC;YAC3B,IAAID,MAAME,WAAW;gBACnBR,MAAM,CAACI,SAAS,GAAG,CAACE,EAAEG,OAAO,CAAC,OAC1BH,EAAEI,KAAK,CAAC,KAAKC,GAAG,CAAC,CAACC,QAAUhB,OAAOgB,UACnCP,EAAEQ,MAAM,GACR;oBAACjB,OAAOU;iBAAG,GACXV,OAAOU;YACb;QACF;QACA,OAAON;IACT;AACF"}

View File

@@ -0,0 +1,178 @@
import { INTERCEPTION_ROUTE_MARKERS } from "../../../../server/future/helpers/interception-routes";
import { escapeStringRegexp } from "../../escape-regexp";
import { removeTrailingSlash } from "./remove-trailing-slash";
const NEXT_QUERY_PARAM_PREFIX = "nxtP";
const NEXT_INTERCEPTION_MARKER_PREFIX = "nxtI";
/**
* Parses a given parameter from a route to a data structure that can be used
* to generate the parametrized route. Examples:
* - `[...slug]` -> `{ key: 'slug', repeat: true, optional: true }`
* - `...slug` -> `{ key: 'slug', repeat: true, optional: false }`
* - `[foo]` -> `{ key: 'foo', repeat: false, optional: true }`
* - `bar` -> `{ key: 'bar', repeat: false, optional: false }`
*/ function parseParameter(param) {
const optional = param.startsWith("[") && param.endsWith("]");
if (optional) {
param = param.slice(1, -1);
}
const repeat = param.startsWith("...");
if (repeat) {
param = param.slice(3);
}
return {
key: param,
repeat,
optional
};
}
function getParametrizedRoute(route) {
const segments = removeTrailingSlash(route).slice(1).split("/");
const groups = {};
let groupIndex = 1;
return {
parameterizedRoute: segments.map((segment)=>{
const markerMatch = INTERCEPTION_ROUTE_MARKERS.find((m)=>segment.startsWith(m));
const paramMatches = segment.match(/\[((?:\[.*\])|.+)\]/) // Check for parameters
;
if (markerMatch && paramMatches) {
const { key, optional, repeat } = parseParameter(paramMatches[1]);
groups[key] = {
pos: groupIndex++,
repeat,
optional
};
return "/" + escapeStringRegexp(markerMatch) + "([^/]+?)";
} else if (paramMatches) {
const { key, repeat, optional } = parseParameter(paramMatches[1]);
groups[key] = {
pos: groupIndex++,
repeat,
optional
};
return repeat ? optional ? "(?:/(.+?))?" : "/(.+?)" : "/([^/]+?)";
} else {
return "/" + escapeStringRegexp(segment);
}
}).join(""),
groups
};
}
/**
* From a normalized route this function generates a regular expression and
* a corresponding groups object intended to be used to store matching groups
* from the regular expression.
*/ export function getRouteRegex(normalizedRoute) {
const { parameterizedRoute, groups } = getParametrizedRoute(normalizedRoute);
return {
re: new RegExp("^" + parameterizedRoute + "(?:/)?$"),
groups: groups
};
}
/**
* Builds a function to generate a minimal routeKey using only a-z and minimal
* number of characters.
*/ function buildGetSafeRouteKey() {
let i = 0;
return ()=>{
let routeKey = "";
let j = ++i;
while(j > 0){
routeKey += String.fromCharCode(97 + (j - 1) % 26);
j = Math.floor((j - 1) / 26);
}
return routeKey;
};
}
function getSafeKeyFromSegment(param) {
let { getSafeRouteKey, segment, routeKeys, keyPrefix } = param;
const { key, optional, repeat } = parseParameter(segment);
// replace any non-word characters since they can break
// the named regex
let cleanedKey = key.replace(/\W/g, "");
if (keyPrefix) {
cleanedKey = "" + keyPrefix + cleanedKey;
}
let invalidKey = false;
// check if the key is still invalid and fallback to using a known
// safe key
if (cleanedKey.length === 0 || cleanedKey.length > 30) {
invalidKey = true;
}
if (!isNaN(parseInt(cleanedKey.slice(0, 1)))) {
invalidKey = true;
}
if (invalidKey) {
cleanedKey = getSafeRouteKey();
}
if (keyPrefix) {
routeKeys[cleanedKey] = "" + keyPrefix + key;
} else {
routeKeys[cleanedKey] = "" + key;
}
return repeat ? optional ? "(?:/(?<" + cleanedKey + ">.+?))?" : "/(?<" + cleanedKey + ">.+?)" : "/(?<" + cleanedKey + ">[^/]+?)";
}
function getNamedParametrizedRoute(route, prefixRouteKeys) {
const segments = removeTrailingSlash(route).slice(1).split("/");
const getSafeRouteKey = buildGetSafeRouteKey();
const routeKeys = {};
return {
namedParameterizedRoute: segments.map((segment)=>{
const hasInterceptionMarker = INTERCEPTION_ROUTE_MARKERS.some((m)=>segment.startsWith(m));
const paramMatches = segment.match(/\[((?:\[.*\])|.+)\]/) // Check for parameters
;
if (hasInterceptionMarker && paramMatches) {
return getSafeKeyFromSegment({
getSafeRouteKey,
segment: paramMatches[1],
routeKeys,
keyPrefix: prefixRouteKeys ? NEXT_INTERCEPTION_MARKER_PREFIX : undefined
});
} else if (paramMatches) {
return getSafeKeyFromSegment({
getSafeRouteKey,
segment: paramMatches[1],
routeKeys,
keyPrefix: prefixRouteKeys ? NEXT_QUERY_PARAM_PREFIX : undefined
});
} else {
return "/" + escapeStringRegexp(segment);
}
}).join(""),
routeKeys
};
}
/**
* This function extends `getRouteRegex` generating also a named regexp where
* each group is named along with a routeKeys object that indexes the assigned
* named group with its corresponding key. When the routeKeys need to be
* prefixed to uniquely identify internally the "prefixRouteKey" arg should
* be "true" currently this is only the case when creating the routes-manifest
* during the build
*/ export function getNamedRouteRegex(normalizedRoute, prefixRouteKey) {
const result = getNamedParametrizedRoute(normalizedRoute, prefixRouteKey);
return {
...getRouteRegex(normalizedRoute),
namedRegex: "^" + result.namedParameterizedRoute + "(?:/)?$",
routeKeys: result.routeKeys
};
}
/**
* Generates a named regexp.
* This is intended to be using for build time only.
*/ export function getNamedMiddlewareRegex(normalizedRoute, options) {
const { parameterizedRoute } = getParametrizedRoute(normalizedRoute);
const { catchAll = true } = options;
if (parameterizedRoute === "/") {
let catchAllRegex = catchAll ? ".*" : "";
return {
namedRegex: "^/" + catchAllRegex + "$"
};
}
const { namedParameterizedRoute } = getNamedParametrizedRoute(normalizedRoute, false);
let catchAllGroupedRegex = catchAll ? "(?:(/.*)?)" : "";
return {
namedRegex: "^" + namedParameterizedRoute + catchAllGroupedRegex + "$"
};
}
//# sourceMappingURL=route-regex.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/route-regex.ts"],"names":["INTERCEPTION_ROUTE_MARKERS","escapeStringRegexp","removeTrailingSlash","NEXT_QUERY_PARAM_PREFIX","NEXT_INTERCEPTION_MARKER_PREFIX","parseParameter","param","optional","startsWith","endsWith","slice","repeat","key","getParametrizedRoute","route","segments","split","groups","groupIndex","parameterizedRoute","map","segment","markerMatch","find","m","paramMatches","match","pos","join","getRouteRegex","normalizedRoute","re","RegExp","buildGetSafeRouteKey","i","routeKey","j","String","fromCharCode","Math","floor","getSafeKeyFromSegment","getSafeRouteKey","routeKeys","keyPrefix","cleanedKey","replace","invalidKey","length","isNaN","parseInt","getNamedParametrizedRoute","prefixRouteKeys","namedParameterizedRoute","hasInterceptionMarker","some","undefined","getNamedRouteRegex","prefixRouteKey","result","namedRegex","getNamedMiddlewareRegex","options","catchAll","catchAllRegex","catchAllGroupedRegex"],"mappings":"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"}

View File

@@ -0,0 +1,79 @@
import { getNamedRouteRegex } from "./route-regex";
describe("getNamedRouteRegex", ()=>{
it("should handle interception markers adjacent to dynamic path segments", ()=>{
const regex = getNamedRouteRegex("/photos/(.)[author]/[id]", true);
expect(regex.routeKeys).toEqual({
nxtIauthor: "nxtIauthor",
nxtPid: "nxtPid"
});
expect(regex.groups["author"]).toEqual({
pos: 1,
repeat: false,
optional: false
});
expect(regex.groups["id"]).toEqual({
pos: 2,
repeat: false,
optional: false
});
expect(regex.re.test("/photos/(.)next/123")).toBe(true);
});
it("should handle multi-level interception markers", ()=>{
const regex = getNamedRouteRegex("/photos/(..)(..)[author]/[id]", true);
expect(regex.routeKeys).toEqual({
nxtIauthor: "nxtIauthor",
nxtPid: "nxtPid"
});
expect(regex.groups["author"]).toEqual({
pos: 1,
repeat: false,
optional: false
});
expect(regex.groups["id"]).toEqual({
pos: 2,
repeat: false,
optional: false
});
expect(regex.re.test("/photos/(..)(..)next/123")).toBe(true);
});
it("should handle interception markers not adjacent to dynamic path segments", ()=>{
const regex = getNamedRouteRegex("/photos/(.)author/[id]", true);
expect(regex.routeKeys).toEqual({
nxtPid: "nxtPid"
});
expect(regex.groups["author"]).toBeUndefined();
expect(regex.groups["id"]).toEqual({
pos: 1,
repeat: false,
optional: false
});
expect(regex.re.test("/photos/(.)author/123")).toBe(true);
});
it("should handle optional dynamic path segments", ()=>{
const regex = getNamedRouteRegex("/photos/[[id]]", true);
expect(regex.routeKeys).toEqual({
nxtPid: "nxtPid"
});
expect(regex.groups["id"]).toEqual({
pos: 1,
repeat: false,
optional: true
});
});
it("should handle optional catch-all dynamic path segments", ()=>{
const regex = getNamedRouteRegex("/photos/[[...id]]", true);
expect(regex.routeKeys).toEqual({
nxtPid: "nxtPid"
});
expect(regex.groups["id"]).toEqual({
pos: 1,
repeat: true,
optional: true
});
expect(regex.re.test("/photos/1")).toBe(true);
expect(regex.re.test("/photos/1/2/3")).toBe(true);
expect(regex.re.test("/photos")).toBe(true);
});
});
//# sourceMappingURL=route-regex.test.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/route-regex.test.ts"],"names":["getNamedRouteRegex","describe","it","regex","expect","routeKeys","toEqual","nxtIauthor","nxtPid","groups","pos","repeat","optional","re","test","toBe","toBeUndefined"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,gBAAe;AAElDC,SAAS,sBAAsB;IAC7BC,GAAG,wEAAwE;QACzE,MAAMC,QAAQH,mBAAmB,4BAA4B;QAE7DI,OAAOD,MAAME,SAAS,EAAEC,OAAO,CAAC;YAC9BC,YAAY;YACZC,QAAQ;QACV;QAEAJ,OAAOD,MAAMM,MAAM,CAAC,SAAS,EAAEH,OAAO,CAAC;YACrCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;QAEAR,OAAOD,MAAMM,MAAM,CAAC,KAAK,EAAEH,OAAO,CAAC;YACjCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;QAEAR,OAAOD,MAAMU,EAAE,CAACC,IAAI,CAAC,wBAAwBC,IAAI,CAAC;IACpD;IAEAb,GAAG,kDAAkD;QACnD,MAAMC,QAAQH,mBAAmB,iCAAiC;QAElEI,OAAOD,MAAME,SAAS,EAAEC,OAAO,CAAC;YAC9BC,YAAY;YACZC,QAAQ;QACV;QAEAJ,OAAOD,MAAMM,MAAM,CAAC,SAAS,EAAEH,OAAO,CAAC;YACrCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;QAEAR,OAAOD,MAAMM,MAAM,CAAC,KAAK,EAAEH,OAAO,CAAC;YACjCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;QAEAR,OAAOD,MAAMU,EAAE,CAACC,IAAI,CAAC,6BAA6BC,IAAI,CAAC;IACzD;IAEAb,GAAG,4EAA4E;QAC7E,MAAMC,QAAQH,mBAAmB,0BAA0B;QAE3DI,OAAOD,MAAME,SAAS,EAAEC,OAAO,CAAC;YAC9BE,QAAQ;QACV;QAEAJ,OAAOD,MAAMM,MAAM,CAAC,SAAS,EAAEO,aAAa;QAE5CZ,OAAOD,MAAMM,MAAM,CAAC,KAAK,EAAEH,OAAO,CAAC;YACjCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;QAEAR,OAAOD,MAAMU,EAAE,CAACC,IAAI,CAAC,0BAA0BC,IAAI,CAAC;IACtD;IAEAb,GAAG,gDAAgD;QACjD,MAAMC,QAAQH,mBAAmB,kBAAkB;QAEnDI,OAAOD,MAAME,SAAS,EAAEC,OAAO,CAAC;YAC9BE,QAAQ;QACV;QAEAJ,OAAOD,MAAMM,MAAM,CAAC,KAAK,EAAEH,OAAO,CAAC;YACjCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;IACF;IAEAV,GAAG,0DAA0D;QAC3D,MAAMC,QAAQH,mBAAmB,qBAAqB;QAEtDI,OAAOD,MAAME,SAAS,EAAEC,OAAO,CAAC;YAC9BE,QAAQ;QACV;QAEAJ,OAAOD,MAAMM,MAAM,CAAC,KAAK,EAAEH,OAAO,CAAC;YACjCI,KAAK;YACLC,QAAQ;YACRC,UAAU;QACZ;QAEAR,OAAOD,MAAMU,EAAE,CAACC,IAAI,CAAC,cAAcC,IAAI,CAAC;QACxCX,OAAOD,MAAMU,EAAE,CAACC,IAAI,CAAC,kBAAkBC,IAAI,CAAC;QAC5CX,OAAOD,MAAMU,EAAE,CAACC,IAAI,CAAC,YAAYC,IAAI,CAAC;IACxC;AACF"}

View File

@@ -0,0 +1,160 @@
class UrlNode {
insert(urlPath) {
this._insert(urlPath.split("/").filter(Boolean), [], false);
}
smoosh() {
return this._smoosh();
}
_smoosh(prefix) {
if (prefix === void 0) prefix = "/";
const childrenPaths = [
...this.children.keys()
].sort();
if (this.slugName !== null) {
childrenPaths.splice(childrenPaths.indexOf("[]"), 1);
}
if (this.restSlugName !== null) {
childrenPaths.splice(childrenPaths.indexOf("[...]"), 1);
}
if (this.optionalRestSlugName !== null) {
childrenPaths.splice(childrenPaths.indexOf("[[...]]"), 1);
}
const routes = childrenPaths.map((c)=>this.children.get(c)._smoosh("" + prefix + c + "/")).reduce((prev, curr)=>[
...prev,
...curr
], []);
if (this.slugName !== null) {
routes.push(...this.children.get("[]")._smoosh(prefix + "[" + this.slugName + "]/"));
}
if (!this.placeholder) {
const r = prefix === "/" ? "/" : prefix.slice(0, -1);
if (this.optionalRestSlugName != null) {
throw new Error('You cannot define a route with the same specificity as a optional catch-all route ("' + r + '" and "' + r + "[[..." + this.optionalRestSlugName + ']]").');
}
routes.unshift(r);
}
if (this.restSlugName !== null) {
routes.push(...this.children.get("[...]")._smoosh(prefix + "[..." + this.restSlugName + "]/"));
}
if (this.optionalRestSlugName !== null) {
routes.push(...this.children.get("[[...]]")._smoosh(prefix + "[[..." + this.optionalRestSlugName + "]]/"));
}
return routes;
}
_insert(urlPaths, slugNames, isCatchAll) {
if (urlPaths.length === 0) {
this.placeholder = false;
return;
}
if (isCatchAll) {
throw new Error("Catch-all must be the last part of the URL.");
}
// The next segment in the urlPaths list
let nextSegment = urlPaths[0];
// Check if the segment matches `[something]`
if (nextSegment.startsWith("[") && nextSegment.endsWith("]")) {
// Strip `[` and `]`, leaving only `something`
let segmentName = nextSegment.slice(1, -1);
let isOptional = false;
if (segmentName.startsWith("[") && segmentName.endsWith("]")) {
// Strip optional `[` and `]`, leaving only `something`
segmentName = segmentName.slice(1, -1);
isOptional = true;
}
if (segmentName.startsWith("...")) {
// Strip `...`, leaving only `something`
segmentName = segmentName.substring(3);
isCatchAll = true;
}
if (segmentName.startsWith("[") || segmentName.endsWith("]")) {
throw new Error("Segment names may not start or end with extra brackets ('" + segmentName + "').");
}
if (segmentName.startsWith(".")) {
throw new Error("Segment names may not start with erroneous periods ('" + segmentName + "').");
}
function handleSlug(previousSlug, nextSlug) {
if (previousSlug !== null) {
// If the specific segment already has a slug but the slug is not `something`
// This prevents collisions like:
// pages/[post]/index.js
// pages/[id]/index.js
// Because currently multiple dynamic params on the same segment level are not supported
if (previousSlug !== nextSlug) {
// TODO: This error seems to be confusing for users, needs an error link, the description can be based on above comment.
throw new Error("You cannot use different slug names for the same dynamic path ('" + previousSlug + "' !== '" + nextSlug + "').");
}
}
slugNames.forEach((slug)=>{
if (slug === nextSlug) {
throw new Error('You cannot have the same slug name "' + nextSlug + '" repeat within a single dynamic path');
}
if (slug.replace(/\W/g, "") === nextSegment.replace(/\W/g, "")) {
throw new Error('You cannot have the slug names "' + slug + '" and "' + nextSlug + '" differ only by non-word symbols within a single dynamic path');
}
});
slugNames.push(nextSlug);
}
if (isCatchAll) {
if (isOptional) {
if (this.restSlugName != null) {
throw new Error('You cannot use both an required and optional catch-all route at the same level ("[...' + this.restSlugName + ']" and "' + urlPaths[0] + '" ).');
}
handleSlug(this.optionalRestSlugName, segmentName);
// slugName is kept as it can only be one particular slugName
this.optionalRestSlugName = segmentName;
// nextSegment is overwritten to [[...]] so that it can later be sorted specifically
nextSegment = "[[...]]";
} else {
if (this.optionalRestSlugName != null) {
throw new Error('You cannot use both an optional and required catch-all route at the same level ("[[...' + this.optionalRestSlugName + ']]" and "' + urlPaths[0] + '").');
}
handleSlug(this.restSlugName, segmentName);
// slugName is kept as it can only be one particular slugName
this.restSlugName = segmentName;
// nextSegment is overwritten to [...] so that it can later be sorted specifically
nextSegment = "[...]";
}
} else {
if (isOptional) {
throw new Error('Optional route parameters are not yet supported ("' + urlPaths[0] + '").');
}
handleSlug(this.slugName, segmentName);
// slugName is kept as it can only be one particular slugName
this.slugName = segmentName;
// nextSegment is overwritten to [] so that it can later be sorted specifically
nextSegment = "[]";
}
}
// If this UrlNode doesn't have the nextSegment yet we create a new child UrlNode
if (!this.children.has(nextSegment)) {
this.children.set(nextSegment, new UrlNode());
}
this.children.get(nextSegment)._insert(urlPaths.slice(1), slugNames, isCatchAll);
}
constructor(){
this.placeholder = true;
this.children = new Map();
this.slugName = null;
this.restSlugName = null;
this.optionalRestSlugName = null;
}
}
export function getSortedRoutes(normalizedPages) {
// First the UrlNode is created, and every UrlNode can have only 1 dynamic segment
// Eg you can't have pages/[post]/abc.js and pages/[hello]/something-else.js
// Only 1 dynamic segment per nesting level
// So in the case that is test/integration/dynamic-routing it'll be this:
// pages/[post]/comments.js
// pages/blog/[post]/comment/[id].js
// Both are fine because `pages/[post]` and `pages/blog` are on the same level
// So in this case `UrlNode` created here has `this.slugName === 'post'`
// And since your PR passed through `slugName` as an array basically it'd including it in too many possibilities
// Instead what has to be passed through is the upwards path's dynamic names
const root = new UrlNode();
// Here the `root` gets injected multiple paths, and insert will break them up into sublevels
normalizedPages.forEach((pagePath)=>root.insert(pagePath));
// Smoosh will then sort those sublevels up to the point where you get the correct route definition priority
return root.smoosh();
}
//# sourceMappingURL=sorted-routes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../src/shared/lib/router/utils/sorted-routes.ts"],"names":["UrlNode","insert","urlPath","_insert","split","filter","Boolean","smoosh","_smoosh","prefix","childrenPaths","children","keys","sort","slugName","splice","indexOf","restSlugName","optionalRestSlugName","routes","map","c","get","reduce","prev","curr","push","placeholder","r","slice","Error","unshift","urlPaths","slugNames","isCatchAll","length","nextSegment","startsWith","endsWith","segmentName","isOptional","substring","handleSlug","previousSlug","nextSlug","forEach","slug","replace","has","set","Map","getSortedRoutes","normalizedPages","root","pagePath"],"mappings":"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"}