"use strict"; /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.writeRedirectFile = exports.toRedirectFiles = exports.createToUrl = void 0; const tslib_1 = require("tslib"); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const path_1 = tslib_1.__importDefault(require("path")); const lodash_1 = tslib_1.__importDefault(require("lodash")); const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger")); const utils_1 = require("@docusaurus/utils"); const createRedirectPageContent_1 = tslib_1.__importDefault(require("./createRedirectPageContent")); function createToUrl(baseUrl, to) { if (to.startsWith('/')) { return (0, utils_1.normalizeUrl)([baseUrl, to]); } return to; } exports.createToUrl = createToUrl; // Create redirect file path // Make sure this path has lower precedence over the original file path when // served by host providers! // Otherwise it can produce infinite redirect loops! // // See https://github.com/facebook/docusaurus/issues/5055 // See https://github.com/facebook/docusaurus/pull/5085 // See https://github.com/facebook/docusaurus/pull/5102 function getRedirectFilePath(fromPath, trailingSlash) { const fileName = path_1.default.basename(fromPath); const filePath = path_1.default.dirname(fromPath); // Edge case for https://github.com/facebook/docusaurus/pull/5102 // If the redirect source path is /xyz, with file /xyz.html // We can't write the redirect file at /xyz.html/index.html because for Unix // FS, a file/folder can't have the same name "xyz.html" // The only possible solution for a redirect file is thus /xyz.html.html (I // know, looks suspicious) if (trailingSlash === false && fileName.endsWith('.html')) { return path_1.default.join(filePath, `${fileName}.html`); } // If the target path is /xyz, with file /xyz/index.html, we don't want the // redirect file to be /xyz.html, otherwise it would be picked in priority and // the redirect file would redirect to itself. We prefer the redirect file to // be /xyz.html/index.html, served with lower priority for most static hosting // tools return path_1.default.join(filePath, `${fileName}/index.html`); } function toRedirectFiles(redirects, pluginContext, trailingSlash) { // Perf: avoid rendering the template twice with the exact same "props" // We might create multiple redirect pages for the same destination url // note: the first fn arg is the cache key! const createPageContentMemoized = lodash_1.default.memoize((toUrl) => (0, createRedirectPageContent_1.default)({ toUrl })); const createFileMetadata = (redirect) => { const fileRelativePath = getRedirectFilePath(redirect.from, trailingSlash); const fileAbsolutePath = path_1.default.join(pluginContext.outDir, fileRelativePath); const toUrl = createToUrl(pluginContext.baseUrl, redirect.to); const fileContent = createPageContentMemoized(toUrl); return { ...redirect, fileAbsolutePath, fileContent, }; }; return redirects.map(createFileMetadata); } exports.toRedirectFiles = toRedirectFiles; async function writeRedirectFile(file) { try { // User-friendly security to prevent file overrides if (await fs_extra_1.default.pathExists(file.fileAbsolutePath)) { throw new Error('The redirect plugin is not supposed to override existing files.'); } await fs_extra_1.default.outputFile(file.fileAbsolutePath, file.fileContent, // Hard security to prevent file overrides // See https://stackoverflow.com/a/34187712/82609 { flag: 'wx' }); } catch (err) { logger_1.default.error `Redirect file creation error for path=${file.fileAbsolutePath}.`; throw err; } } exports.writeRedirectFile = writeRedirectFile; async function writeRedirectFiles(redirectFiles) { await Promise.all(redirectFiles.map(writeRedirectFile)); } exports.default = writeRedirectFiles;