217 lines
7.9 KiB
JavaScript
217 lines
7.9 KiB
JavaScript
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
var utils = require('../shared/utils.js');
|
|
|
|
function getInternalTemplate(pathnames, pathname, locale) {
|
|
const sortedPathnames = utils.getSortedPathnames(Object.keys(pathnames));
|
|
|
|
// Try to find a localized pathname that matches
|
|
for (const internalPathname of sortedPathnames) {
|
|
const localizedPathnamesOrPathname = pathnames[internalPathname];
|
|
if (typeof localizedPathnamesOrPathname === 'string') {
|
|
const localizedPathname = localizedPathnamesOrPathname;
|
|
if (utils.matchesPathname(localizedPathname, pathname)) {
|
|
return [undefined, internalPathname];
|
|
}
|
|
} else {
|
|
// Prefer the entry with the current locale in case multiple
|
|
// localized pathnames match the current pathname
|
|
const sortedEntries = Object.entries(localizedPathnamesOrPathname);
|
|
const curLocaleIndex = sortedEntries.findIndex(_ref => {
|
|
let [entryLocale] = _ref;
|
|
return entryLocale === locale;
|
|
});
|
|
if (curLocaleIndex > 0) {
|
|
sortedEntries.unshift(sortedEntries.splice(curLocaleIndex, 1)[0]);
|
|
}
|
|
for (const [entryLocale, entryPathname] of sortedEntries) {
|
|
if (utils.matchesPathname(entryPathname, pathname)) {
|
|
return [entryLocale, internalPathname];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try to find an internal pathname that matches (this can be the case
|
|
// if all localized pathnames are different from the internal pathnames)
|
|
for (const internalPathname of Object.keys(pathnames)) {
|
|
if (utils.matchesPathname(internalPathname, pathname)) {
|
|
return [undefined, internalPathname];
|
|
}
|
|
}
|
|
|
|
// No match
|
|
return [undefined, undefined];
|
|
}
|
|
function formatTemplatePathname(sourcePathname, sourceTemplate, targetTemplate, prefix) {
|
|
const params = getRouteParams(sourceTemplate, sourcePathname);
|
|
let targetPathname = '';
|
|
targetPathname += formatPathnameTemplate(targetTemplate, params);
|
|
|
|
// A pathname with an optional catchall like `/categories/[[...slug]]`
|
|
// should be normalized to `/categories` if the catchall is not present
|
|
// and no trailing slash is configured
|
|
targetPathname = utils.normalizeTrailingSlash(targetPathname);
|
|
return targetPathname;
|
|
}
|
|
|
|
/**
|
|
* Removes potential prefixes from the pathname.
|
|
*/
|
|
function getNormalizedPathname(pathname, locales, localePrefix) {
|
|
// Add trailing slash for consistent handling
|
|
// both for the root as well as nested paths
|
|
if (!pathname.endsWith('/')) {
|
|
pathname += '/';
|
|
}
|
|
const localePrefixes = getLocalePrefixes(locales, localePrefix);
|
|
const regex = new RegExp("^(".concat(localePrefixes.map(_ref2 => {
|
|
let [, prefix] = _ref2;
|
|
return prefix.replaceAll('/', '\\/');
|
|
}).join('|'), ")/(.*)"), 'i');
|
|
const match = pathname.match(regex);
|
|
let result = match ? '/' + match[2] : pathname;
|
|
if (result !== '/') {
|
|
result = utils.normalizeTrailingSlash(result);
|
|
}
|
|
return result;
|
|
}
|
|
function getLocalePrefixes(locales, localePrefix) {
|
|
let sort = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
const prefixes = locales.map(locale => [locale, utils.getLocalePrefix(locale, localePrefix)]);
|
|
if (sort) {
|
|
// More specific ones first
|
|
prefixes.sort((a, b) => b[1].length - a[1].length);
|
|
}
|
|
return prefixes;
|
|
}
|
|
function getPathnameMatch(pathname, locales, localePrefix) {
|
|
const localePrefixes = getLocalePrefixes(locales, localePrefix);
|
|
for (const [locale, prefix] of localePrefixes) {
|
|
let exact, matches;
|
|
if (pathname === prefix || pathname.startsWith(prefix + '/')) {
|
|
exact = matches = true;
|
|
} else {
|
|
const normalizedPathname = pathname.toLowerCase();
|
|
const normalizedPrefix = prefix.toLowerCase();
|
|
if (normalizedPathname === normalizedPrefix || normalizedPathname.startsWith(normalizedPrefix + '/')) {
|
|
exact = false;
|
|
matches = true;
|
|
}
|
|
}
|
|
if (matches) {
|
|
return {
|
|
locale,
|
|
prefix,
|
|
matchedPrefix: pathname.slice(0, prefix.length),
|
|
exact
|
|
};
|
|
}
|
|
}
|
|
}
|
|
function getRouteParams(template, pathname) {
|
|
const normalizedPathname = utils.normalizeTrailingSlash(pathname);
|
|
const normalizedTemplate = utils.normalizeTrailingSlash(template);
|
|
const regex = utils.templateToRegex(normalizedTemplate);
|
|
const match = regex.exec(normalizedPathname);
|
|
if (!match) return undefined;
|
|
const params = {};
|
|
for (let i = 1; i < match.length; i++) {
|
|
var _normalizedTemplate$m;
|
|
const key = (_normalizedTemplate$m = normalizedTemplate.match(/\[([^\]]+)\]/g)) === null || _normalizedTemplate$m === void 0 ? void 0 : _normalizedTemplate$m[i - 1].replace(/[[\]]/g, '');
|
|
if (key) params[key] = match[i];
|
|
}
|
|
return params;
|
|
}
|
|
function formatPathnameTemplate(template, params) {
|
|
if (!params) return template;
|
|
|
|
// Simplify syntax for optional catchall ('[[...slug]]') so
|
|
// we can replace the value with simple interpolation
|
|
template = template.replace(/\[\[/g, '[').replace(/\]\]/g, ']');
|
|
let result = template;
|
|
Object.entries(params).forEach(_ref3 => {
|
|
let [key, value] = _ref3;
|
|
result = result.replace("[".concat(key, "]"), value);
|
|
});
|
|
return result;
|
|
}
|
|
function formatPathname(pathname, prefix, search) {
|
|
let result = pathname;
|
|
if (prefix) {
|
|
result = utils.prefixPathname(prefix, result);
|
|
}
|
|
if (search) {
|
|
result += search;
|
|
}
|
|
return result;
|
|
}
|
|
function getHost(requestHeaders) {
|
|
var _ref4, _requestHeaders$get;
|
|
return (_ref4 = (_requestHeaders$get = requestHeaders.get('x-forwarded-host')) !== null && _requestHeaders$get !== void 0 ? _requestHeaders$get : requestHeaders.get('host')) !== null && _ref4 !== void 0 ? _ref4 : undefined;
|
|
}
|
|
function isLocaleSupportedOnDomain(locale, domain) {
|
|
return domain.defaultLocale === locale || !domain.locales || domain.locales.includes(locale);
|
|
}
|
|
function getBestMatchingDomain(curHostDomain, locale, domainsConfig) {
|
|
let domainConfig;
|
|
|
|
// Prio 1: Stay on current domain
|
|
if (curHostDomain && isLocaleSupportedOnDomain(locale, curHostDomain)) {
|
|
domainConfig = curHostDomain;
|
|
}
|
|
|
|
// Prio 2: Use alternative domain with matching default locale
|
|
if (!domainConfig) {
|
|
domainConfig = domainsConfig.find(cur => cur.defaultLocale === locale);
|
|
}
|
|
|
|
// Prio 3: Use alternative domain with restricted matching locale
|
|
if (!domainConfig) {
|
|
domainConfig = domainsConfig.find(cur => {
|
|
var _cur$locales;
|
|
return (_cur$locales = cur.locales) === null || _cur$locales === void 0 ? void 0 : _cur$locales.includes(locale);
|
|
});
|
|
}
|
|
|
|
// Prio 4: Stay on the current domain if it supports all locales
|
|
if (!domainConfig && (curHostDomain === null || curHostDomain === void 0 ? void 0 : curHostDomain.locales) == null) {
|
|
domainConfig = curHostDomain;
|
|
}
|
|
|
|
// Prio 5: Use alternative domain that supports all locales
|
|
if (!domainConfig) {
|
|
domainConfig = domainsConfig.find(cur => !cur.locales);
|
|
}
|
|
return domainConfig;
|
|
}
|
|
function applyBasePath(pathname, basePath) {
|
|
return utils.normalizeTrailingSlash(basePath + pathname);
|
|
}
|
|
function getLocaleAsPrefix(locale) {
|
|
return "/".concat(locale);
|
|
}
|
|
function sanitizePathname(pathname) {
|
|
// Sanitize malicious URIs, e.g.:
|
|
// '/en/\\example.org → /en/%5C%5Cexample.org'
|
|
// '/en////example.org → /en/example.org'
|
|
return pathname.replace(/\\/g, '%5C').replace(/\/+/g, '/');
|
|
}
|
|
|
|
exports.applyBasePath = applyBasePath;
|
|
exports.formatPathname = formatPathname;
|
|
exports.formatPathnameTemplate = formatPathnameTemplate;
|
|
exports.formatTemplatePathname = formatTemplatePathname;
|
|
exports.getBestMatchingDomain = getBestMatchingDomain;
|
|
exports.getHost = getHost;
|
|
exports.getInternalTemplate = getInternalTemplate;
|
|
exports.getLocaleAsPrefix = getLocaleAsPrefix;
|
|
exports.getLocalePrefixes = getLocalePrefixes;
|
|
exports.getNormalizedPathname = getNormalizedPathname;
|
|
exports.getPathnameMatch = getPathnameMatch;
|
|
exports.getRouteParams = getRouteParams;
|
|
exports.isLocaleSupportedOnDomain = isLocaleSupportedOnDomain;
|
|
exports.sanitizePathname = sanitizePathname;
|