next-translate-routes-multi-domain
Version:
Flexible and translated routes for Next.js without custom server
299 lines • 14.8 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.urlToFileUrl = exports.parsePathParts = void 0;
var path_to_regexp_1 = require("path-to-regexp");
var regex_1 = require("../shared/regex");
var ntrData_1 = require("./ntrData");
var removeLangPrefix_1 = require("./removeLangPrefix");
var urlToUrlObject_1 = require("./urlToUrlObject");
var MATCH_TYPE;
(function (MATCH_TYPE) {
MATCH_TYPE["STATIC"] = "static";
MATCH_TYPE["DYNAMIC"] = "dynamic";
MATCH_TYPE["MATCHALL"] = "match-all";
})(MATCH_TYPE || (MATCH_TYPE = {}));
var getEndFilepathParts = function (_a, locale) {
var e_1, _b, _c;
var _d;
var _e = _a.children, children = _e === void 0 ? [] : _e;
try {
for (var children_1 = __values(children), children_1_1 = children_1.next(); !children_1_1.done; children_1_1 = children_1.next()) {
var child = children_1_1.value;
var path = child.paths[locale] || child.paths.default;
if (path === 'index') {
return { parsedPathParts: [], additionalQuery: {}, firstMatchType: MATCH_TYPE.STATIC };
}
if (regex_1.ignoreSegmentPathRegex.test(path) && ((_d = child.children) === null || _d === void 0 ? void 0 : _d.length)) {
var descendantResult = getEndFilepathParts(child, locale);
if (descendantResult) {
return __assign(__assign({}, descendantResult), { parsedPathParts: __spreadArray([child.name], __read(descendantResult.parsedPathParts), false) });
}
}
var optionalMatchAllToken = (0, path_to_regexp_1.parse)(path).find(function (ptrToken) { return typeof ptrToken === 'object' && ptrToken.modifier === '*'; });
if (optionalMatchAllToken) {
return {
parsedPathParts: [child.name],
additionalQuery: (_c = {}, _c[optionalMatchAllToken.name] = [], _c),
firstMatchType: MATCH_TYPE.MATCHALL,
};
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (children_1_1 && !children_1_1.done && (_b = children_1.return)) _b.call(children_1);
}
finally { if (e_1) throw e_1.error; }
}
return undefined;
};
/**
* Recursively parse paths to identify the matching file path, and extract the parameters
*
* We must do this taking care of the priorities:
* 1. static match among the current route branch children
* 2. static match among among the descendants of a child that is path-ignored
* 3. dynamic match among the current route branch children
* 4. dynamic match among among the descendants of a child that is path-ignored
* 5. match all match among the current route branch children
* 6. match all match among among the descendants of a child that is path-ignored
*/
var parsePathParts = function (_a) {
var e_2, _b, e_3, _c;
var locale = _a.locale, _d = _a.pathParts, pathParts = _d === void 0 ? [] : _d, routeBranch = _a.routeBranch;
var children = routeBranch.children;
// If there is no path parts left to parse
if (pathParts.length === 0) {
if (!(children === null || children === void 0 ? void 0 : children.length)) {
// The current routeBranch have no children, this is a match
return { parsedPathParts: [], additionalQuery: {}, firstMatchType: MATCH_TYPE.STATIC };
}
return getEndFilepathParts(routeBranch, locale);
}
var currentPathPart = pathParts[0];
var nextPathParts = pathParts.slice(1);
// Ignore empty path parts
if (!currentPathPart) {
return (0, exports.parsePathParts)({ locale: locale, pathParts: nextPathParts, routeBranch: routeBranch });
}
// We are looking for the route matching the current path part among ther routeBranch children
// It can be a static path part, or a dynamic path part (`[slug]` or `[...path]` for exemple)
if (!(children === null || children === void 0 ? void 0 : children.length)) {
// No match possible
return undefined;
}
// 1. Lets first look for static matches among the current children
/** We will store here candidates that does not match statically */
var delayedCandidates = [];
var matchAllCandidate = undefined;
try {
for (var children_2 = __values(children), children_2_1 = children_2.next(); !children_2_1.done; children_2_1 = children_2.next()) {
var candidate = children_2_1.value;
var path = candidate.paths[locale] || candidate.paths.default;
// Does the candidate statically match?
if (path === currentPathPart) {
// It does! But does its children match too?
var childrenParsedPathParts = (0, exports.parsePathParts)({ locale: locale, pathParts: nextPathParts, routeBranch: candidate });
if (childrenParsedPathParts) {
// They do! Let's return the result immediately
return __assign(__assign({}, childrenParsedPathParts), { parsedPathParts: __spreadArray([candidate.name], __read(childrenParsedPathParts.parsedPathParts), false), firstMatchType: MATCH_TYPE.STATIC });
}
}
var isAnyDynamicPathPattern = regex_1.anyDynamicPathPatternPartRegex.test(path);
var isIgnorePathPattern = regex_1.ignoreSegmentPathRegex.test(path);
// Does the candidate path is static even if it does not match?
if (!isAnyDynamicPathPattern && !isIgnorePathPattern) {
// This candidate is static and does not match the currentPathPart: no need to check further
continue;
}
// So this candidate is not static
// Let's classify it to use it later and first look for a static match (priority):
// is it path-ignored, dynamic, or match-all?
if (isIgnorePathPattern) {
// It is path-ignored, let's unshift (hight priority) it among the delayedCandidates
delayedCandidates.unshift({ candidate: candidate, isPathIgnored: true });
continue;
}
else if ((0, path_to_regexp_1.parse)(path).some(function (ptrToken) { return typeof ptrToken === 'object' && ['+', '*'].includes(ptrToken.modifier); })) {
// It is a match-all path: let's store it alone (there can be only one)
matchAllCandidate = candidate;
}
else {
// It is a dynamic path, let's push (low priority) it among the delayedCandidates
delayedCandidates.push({ candidate: candidate, isPathIgnored: false });
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (children_2_1 && !children_2_1.done && (_b = children_2.return)) _b.call(children_2);
}
finally { if (e_2) throw e_2.error; }
}
// Now we know that there is no static match among these children
// 2. & 3.Let's take care of these delayed candidates
/**
* We will store here the non static matches from path-ignored candidates
* to handle them if there is not dynamic match among the current children
*/
var pathIgnoredResults = {};
try {
for (var delayedCandidates_1 = __values(delayedCandidates), delayedCandidates_1_1 = delayedCandidates_1.next(); !delayedCandidates_1_1.done; delayedCandidates_1_1 = delayedCandidates_1.next()) {
var _e = delayedCandidates_1_1.value, candidate = _e.candidate, isPathIgnored = _e.isPathIgnored;
if (isPathIgnored) {
// 2. Let's look among the descendants of this path-ignored candidate
var rawResult = (0, exports.parsePathParts)({
locale: locale,
routeBranch: candidate,
pathParts: pathParts,
});
if (rawResult) {
// Found a match
var result = __assign(__assign({}, rawResult), { parsedPathParts: __spreadArray([candidate.name], __read(rawResult.parsedPathParts), false) });
if (rawResult.firstMatchType === MATCH_TYPE.STATIC) {
// Static match: that's it, let's take this one
return result;
}
else {
// Let's store it for now, we will use it if we don't find something better
pathIgnoredResults[rawResult.firstMatchType] = result;
}
}
}
else {
// 3. If we are here, it means that we did not find any static match, even among path-ignored candidates descendants,
// because we sorted the candidates in the delayedCandidates array: first the path-ignored candidates, then the dynamic ones.
var path = candidate.paths[locale] || candidate.paths.default;
var match = (0, path_to_regexp_1.match)(path)(currentPathPart);
if (match) {
// It matches! But does its children match too?
var childrenParsedPathParts = (0, exports.parsePathParts)({ locale: locale, pathParts: nextPathParts, routeBranch: candidate });
if (childrenParsedPathParts) {
// They do! Let's return the result immediately
return {
parsedPathParts: __spreadArray([candidate.name], __read(childrenParsedPathParts.parsedPathParts), false),
additionalQuery: __assign(__assign({}, childrenParsedPathParts.additionalQuery), match.params),
firstMatchType: MATCH_TYPE.DYNAMIC,
};
}
}
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (delayedCandidates_1_1 && !delayedCandidates_1_1.done && (_c = delayedCandidates_1.return)) _c.call(delayedCandidates_1);
}
finally { if (e_3) throw e_3.error; }
}
// 4. Do we have a dynamic match stored in the pathIgnoredMatches?
if (pathIgnoredResults[MATCH_TYPE.DYNAMIC]) {
// Yes, let's return it
return pathIgnoredResults[MATCH_TYPE.DYNAMIC];
}
// 5. Do we have a matchAllCandidate stored?
if (matchAllCandidate) {
// Yes.
var path = matchAllCandidate.paths[locale] || matchAllCandidate.paths.default;
var match = (0, path_to_regexp_1.match)('/' + path)('/' + pathParts.join('/'));
if (match) {
// It matches! And it does not have children (or should not).
return {
parsedPathParts: [matchAllCandidate.name],
additionalQuery: match.params,
firstMatchType: MATCH_TYPE.MATCHALL,
};
}
}
// 6. Do we have a match all match stored in the pathIgnoredMatches?
if (pathIgnoredResults[MATCH_TYPE.DYNAMIC]) {
// Yes, let's return it
return pathIgnoredResults[MATCH_TYPE.DYNAMIC];
}
// Still there? No match then.
return undefined;
};
exports.parsePathParts = parsePathParts;
/**
* Parse a translated url to get the corresponding file url (UrlObject)
*
* Ex: `urlToFileUrl('/fr/mon/url/de/france', 'fr')` => `{ pathname: '/my/url/from/[country], query: { country: 'france' } }`
*
* @param url The url to parse: can be a string, an URL or an UrlObject
* @param locale (optional) The locale corresponding to the url translation.
* If omitted, urlToFileUrl will look for the locale in the first path part.
* If it does not match a locale, urlToFileUrl will use the default locale.
*
* @returns The file path based, Next.js format, url in UrlObject format
* if the url successfully matched a file path, and undefined otherwise
*/
var urlToFileUrl = function (url, locale) {
var _a = (0, ntrData_1.getNtrData)(), routesTree = _a.routesTree, defaultLocale = _a.defaultLocale, locales = _a.locales;
var _b = (0, urlToUrlObject_1.urlToUrlObject)(url), pathname = _b.pathname, query = _b.query, hash = _b.hash;
if (pathname && regex_1.anyDynamicFilepathPartsRegex.exec(pathname)) {
// Not sure if we should return undefined instead. Or throw?
return { pathname: pathname, query: query, hash: hash };
}
var result = (0, exports.parsePathParts)({
locale: locale || defaultLocale || locales[0],
routeBranch: routesTree,
pathParts: (0, removeLangPrefix_1.removeLangPrefix)(pathname || '/', true, locale),
});
if (result) {
var parsedPathParts = result.parsedPathParts, additionalQuery = result.additionalQuery;
return __assign({ pathname: "/".concat(parsedPathParts.join('/')), query: __assign(__assign({}, query), additionalQuery) }, (hash && { hash: hash }));
}
return undefined;
};
exports.urlToFileUrl = urlToFileUrl;
//# sourceMappingURL=urlToFileUrl.js.map