@nimpl/getters
Version:
Implementation of server getters in React Server Components without switching to SSR in next.js
107 lines (106 loc) • 4.54 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseParams = exports.INVALID_PARSE = exports.normalizeInterceptingRoutes = exports.parseSegments = exports.normalizePagePath = exports.normalizePathname = void 0;
const normalizePathname = (pathname) => {
const cleanPathname = pathname && new URL(pathname, "http://n").pathname;
const pathnameWithoutTrailingSlash = cleanPathname?.replace(/^(\/.*)\/$/, "$1");
const pathnameWithoutFileType = pathnameWithoutTrailingSlash?.replace(/\/_not-found$/, "");
return pathnameWithoutFileType.endsWith("/") ? pathnameWithoutFileType : pathnameWithoutFileType + "/";
};
exports.normalizePathname = normalizePathname;
const normalizePagePath = (pagePath) => {
const cleanPagePath = pagePath && new URL(pagePath, "http://n").pathname;
const pagePathWithoutFileType = cleanPagePath?.replace(/(\/page|\/_not-found)$/, "/");
const pagePathWithoutGroups = pagePathWithoutFileType
.split("/")
.filter(Boolean)
.filter((segment) => !segment.match(/^(\([^)]+\)$|^\@.+$)/g));
if (pagePathWithoutGroups.length === 0)
return "/";
return "/" + pagePathWithoutGroups.join("/") + "/";
};
exports.normalizePagePath = normalizePagePath;
const parseSegments = (pagePathParts, pathnameParts) => {
const query = pagePathParts.reduce((acc, cur, index) => {
const optionalCatchAllSegment = cur.match(/^\[\[\.\.\.([^\]]+)\]\]$/);
if (optionalCatchAllSegment) {
const key = optionalCatchAllSegment[1];
const segmentParts = pathnameParts.slice(index);
if (segmentParts.length) {
acc[key] = segmentParts;
}
return acc;
}
const catchAllSegment = cur.match(/^\[\.\.\.([^\]]+)\]$/);
if (catchAllSegment) {
const key = catchAllSegment[1];
acc[key] = pathnameParts.slice(index);
return acc;
}
const dynamicSegment = cur.match(/^\[([^\]]+)\]$/);
if (dynamicSegment) {
const key = dynamicSegment[1];
acc[key] = pathnameParts[index];
return acc;
}
return acc;
}, {});
return query;
};
exports.parseSegments = parseSegments;
const normalizeInterceptingRoutes = (pageParts) => {
let skip = 0;
const normilizedParts = [];
for (const pagepart of [...pageParts].reverse()) {
if (skip) {
skip -= 1;
continue;
}
if (pagepart.startsWith("(...)")) {
normilizedParts.push(pagepart.replace(/^\(\.\.\.\)/, ""));
break;
}
else if (pagepart.startsWith("(.)")) {
normilizedParts.push(pagepart.replace(/^\(\.\)/, ""));
}
else if (pagepart.startsWith("(..)")) {
const skipLeafs = pagepart.match(/\(\.\.\)/g);
skip += skipLeafs?.length || 0;
normilizedParts.push(pagepart.replace(/^(\(\.\.\))+/, ""));
}
else {
normilizedParts.push(pagepart);
}
}
return normilizedParts.reverse();
};
exports.normalizeInterceptingRoutes = normalizeInterceptingRoutes;
exports.INVALID_PARSE = Symbol("Invalid Parse");
const isSamePaths = (urlPathnameParts, pagePathParts) => {
for (let i = 0; i < pagePathParts.length; i++) {
const urlPathnamePart = urlPathnameParts[i];
const pagePathPart = pagePathParts[i];
if (pagePathPart.match(/\[\.\.\.[^\]]+\]/))
return true;
if (pagePathPart.match(/\[[^\]]+\]/))
continue;
if (urlPathnamePart !== pagePathPart)
return false;
}
return urlPathnameParts.length === pagePathParts.length;
};
const parseParams = (urlPathname, pagePath) => {
const cleanUrlPathname = (0, exports.normalizePathname)(urlPathname);
const cleanPagePath = (0, exports.normalizePagePath)(pagePath);
const pagePathParts = cleanPagePath.split("/").slice(0, -1);
const pagePathInterceptedParts = (0, exports.normalizeInterceptingRoutes)(pagePathParts);
const pathnameParts = cleanUrlPathname.split("/").slice(0, -1);
const isNotFoundPage = pagePath.match(/\/_not-found\/?$/);
const isCorrectMatched = isNotFoundPage || isSamePaths(pathnameParts, pagePathInterceptedParts);
if (!isCorrectMatched) {
return exports.INVALID_PARSE;
}
const query = (0, exports.parseSegments)(pagePathInterceptedParts, pathnameParts);
return query;
};
exports.parseParams = parseParams;