export function navigationFallback()

in src/msha/routes-engine/rules/navigation-fallback.ts [14:121]


export function navigationFallback(req: http.IncomingMessage, res: http.ServerResponse, navigationFallback: SWAConfigFileNavigationFallback) {
  let originlUrl = req.url;

  logger.silly("checking navigation fallback...");

  // don't process .auth requests
  if (originlUrl?.startsWith("/.auth")) {
    logger.silly(` - request ${chalk.yellow(originlUrl)} is auth`);
    logger.silly(` - ignoring navigation fallback`);
    return false;
  }

  // exit if no rewrite rule provided
  if (!navigationFallback?.rewrite) {
    logger.silly(` - rewrite rule is invalid (got: ${chalk.yellow(navigationFallback?.rewrite)})`);
    logger.silly(` - ignoring navigation fallback`);
    return false;
  }
  // exit if no exclude property provided, or exclude list is empty
  if (!navigationFallback?.exclude || navigationFallback?.exclude?.length === 0) {
    logger.silly(` - exclude rule is invalid (got: ${chalk.yellow(navigationFallback?.exclude)})`);
    logger.silly(` - ignoring navigation fallback`);
    return false;
  }

  // make sure we have a leading / in the URL
  if (navigationFallback.rewrite.startsWith("/") === false) {
    navigationFallback.rewrite = `/${navigationFallback.rewrite}`;
  }

  // is the requested file available on disk?
  const filename = getIndexHtml(originlUrl);
  const filepath = path.join(swaCLIEnv().SWA_CLI_OUTPUT_LOCATION!, filename!);
  const isFileFoundOnDisk = fs.existsSync(filepath);

  logger.silly(` - url: ${chalk.yellow(originlUrl)}`);
  logger.silly(` - file: ${chalk.yellow(filepath)} (exists: ${chalk.yellow(isFileFoundOnDisk)})`);

  // parse the exclusion rules and match at least one rule
  const isMatchedExcludeRule = navigationFallback?.exclude?.some((filter) => {
    if (isValidGlobExpression(filter) === false) {
      logger.silly(` - invalid rule ${chalk.yellow(filter)}`);
      logger.silly(` - mark as no match`);
      return false;
    }

    // we don't support full globs in the config file.
    // add this little utility to convert a wildcard into a valid glob pattern
    const regexp = new RegExp(`^${globToRegExp(filter)}$`);
    const isMatch = regexp.test(originlUrl!);

    logger.silly(`   - rule: ${chalk.yellow(filter)}`);
    logger.silly(`   - regexp: ${chalk.yellow(regexp)}`);
    logger.silly(`   - isRegexpMatch: ${chalk.yellow(isMatch)}`);

    return isMatch;
  });

  logger.silly(` - isMatchedExcludeRule: ${chalk.yellow(isMatchedExcludeRule)}`);

  // rules logic:
  // 1. if no exclude rules are provided, rewrite by default
  // 2. if a file exists on disk, and match exclusion => return it
  // 3. if a file doesn't exist on disk, and match exclusion => 404
  // 4. if a file exists on disk, and doesn't match exclusion => /index.html
  // 5. if a file doesn't exist on disk, and doesn't match exclusion => /index.html

  // note: given the complexity of all possible combinations, don't refactor the code below
  let rewriteUrl = req.url;
  // 1.
  if (!navigationFallback.exclude || navigationFallback.exclude.length === 0) {
    rewriteUrl = navigationFallback.rewrite;

    logger.silly(` - no exclude rules are provided (rewrite by default)`);
    logger.silly(` - url: ${chalk.yellow(rewriteUrl)}`);
  }
  // 2.
  else if (isFileFoundOnDisk === true && isMatchedExcludeRule === true) {
    rewriteUrl = req.url;

    logger.silly(` - file exists on disk, and match exclusion`);
    logger.silly(` - url: ${chalk.yellow(rewriteUrl)}`);
  }
  // 3.
  else if (isFileFoundOnDisk === false && isMatchedExcludeRule === true) {
    res.statusCode = 404;

    logger.silly(` - file doesn't exist on disk, and match exclusion`);
    logger.silly(` - statusCode: ${chalk.yellow(404)}`);
  }
  // 4.
  else if (isFileFoundOnDisk === true && isMatchedExcludeRule === false) {
    rewriteUrl = navigationFallback.rewrite;

    logger.silly(` - file exists on disk, and doesn't match exclusion`);
    logger.silly(` - url: ${chalk.yellow(rewriteUrl)}`);
  }
  // 5.
  else if (isFileFoundOnDisk === false && isMatchedExcludeRule === false) {
    rewriteUrl = navigationFallback.rewrite;

    logger.silly(` - file doesn't exist on disk, and doesn't match exclusion`);
    logger.silly(` - url: ${chalk.yellow(rewriteUrl)}`);
  }

  req.url = rewriteUrl;
  return true;
}