"use strict"; const path = require("path"); const { parse } = require("url"); const querystring = require("querystring"); const getPaths = require("./getPaths"); /** @typedef {import("../index.js").IncomingMessage} IncomingMessage */ /** @typedef {import("../index.js").ServerResponse} ServerResponse */ const cacheStore = new WeakMap(); /** * @param {Function} fn * @param {{ cache?: Map }} [cache] * @returns {any} */ const mem = (fn, { cache = new Map() } = {}) => { /** * @param {any} arguments_ * @return {any} */ const memoized = (...arguments_) => { const [key] = arguments_; const cacheItem = cache.get(key); if (cacheItem) { return cacheItem.data; } const result = fn.apply(void 0, arguments_); cache.set(key, { data: result }); return result; }; cacheStore.set(memoized, cache); return memoized; }; const memoizedParse = mem(parse); /** * @template {IncomingMessage} Request * @template {ServerResponse} Response * @param {import("../index.js").Context} context * @param {string} url * @returns {string | undefined} */ function getFilenameFromUrl(context, url) { const { options } = context; const paths = getPaths(context); let foundFilename; let urlObject; try { // The `url` property of the `request` is contains only `pathname`, `search` and `hash` urlObject = memoizedParse(url, false, true); } catch (_ignoreError) { return; } for (const { publicPath, outputPath } of paths) { let filename; let publicPathObject; try { publicPathObject = memoizedParse(publicPath !== "auto" && publicPath ? publicPath : "/", false, true); } catch (_ignoreError) { // eslint-disable-next-line no-continue continue; } if (urlObject.pathname && urlObject.pathname.startsWith(publicPathObject.pathname)) { filename = outputPath; // Strip the `pathname` property from the `publicPath` option from the start of requested url // `/complex/foo.js` => `foo.js` const pathname = urlObject.pathname.substr(publicPathObject.pathname.length); if (pathname) { filename = path.join(outputPath, querystring.unescape(pathname)); } let fsStats; try { fsStats = /** @type {import("fs").statSync} */ context.outputFileSystem.statSync(filename); } catch (_ignoreError) { // eslint-disable-next-line no-continue continue; } if (fsStats.isFile()) { foundFilename = filename; break; } else if (fsStats.isDirectory() && (typeof options.index === "undefined" || options.index)) { const indexValue = typeof options.index === "undefined" || typeof options.index === "boolean" ? "index.html" : options.index; filename = path.join(filename, indexValue); try { fsStats = /** @type {import("fs").statSync} */ context.outputFileSystem.statSync(filename); } catch (__ignoreError) { // eslint-disable-next-line no-continue continue; } if (fsStats.isFile()) { foundFilename = filename; break; } } } } // eslint-disable-next-line consistent-return return foundFilename; } module.exports = getFilenameFromUrl;