« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/content/dependencies/generateAlbumReleaseInfo.js32
-rw-r--r--src/content/dependencies/generatePageLayout.js6
-rw-r--r--src/content/dependencies/generateReleaseInfoListenLine.js150
-rw-r--r--src/content/dependencies/generateTrackInfoPage.js12
-rw-r--r--src/content/dependencies/generateTrackReleaseInfo.js31
-rw-r--r--src/content/dependencies/listTracksWithLyrics.js2
-rw-r--r--src/data/yaml.js11
-rw-r--r--src/external-links.js27
-rw-r--r--src/static/css/site.css24
-rw-r--r--src/static/js/client/index.js2
-rw-r--r--src/static/js/client/lyrics-switcher.js70
-rw-r--r--src/static/js/rectangles.js42
-rw-r--r--src/strings-default.yaml7
-rw-r--r--src/urls-default.yaml2
-rw-r--r--src/write/build-modes/static-build.js58
15 files changed, 336 insertions, 140 deletions
diff --git a/src/content/dependencies/generateAlbumReleaseInfo.js b/src/content/dependencies/generateAlbumReleaseInfo.js
index 0abb412c..17390c9b 100644
--- a/src/content/dependencies/generateAlbumReleaseInfo.js
+++ b/src/content/dependencies/generateAlbumReleaseInfo.js
@@ -3,7 +3,7 @@ import {accumulateSum, empty} from '#sugar';
 export default {
   contentDependencies: [
     'generateReleaseInfoContributionsLine',
-    'linkExternal',
+    'generateReleaseInfoListenLine',
   ],
 
   extraDependencies: ['html', 'language'],
@@ -20,9 +20,8 @@ export default {
     relations.bannerArtistContributionsLine =
       relation('generateReleaseInfoContributionsLine', album.bannerArtistContribs);
 
-    relations.externalLinks =
-      album.urls.map(url =>
-        relation('linkExternal', url));
+    relations.listenLine =
+      relation('generateReleaseInfoListenLine', album);
 
     return relations;
   },
@@ -87,21 +86,16 @@ export default {
         html.tag('p',
           {[html.onlyIfContent]: true},
 
-          language.$(capsule, 'listenOn', {
-            [language.onlyIfOptions]: ['links'],
-
-            links:
-              language.formatDisjunctionList(
-                relations.externalLinks
-                  .map(link =>
-                    link.slot('context', [
-                      'album',
-                      (data.numTracks === 0
-                        ? 'albumNoTracks'
-                     : data.numTracks === 1
-                        ? 'albumOneTrack'
-                        : 'albumMultipleTracks'),
-                    ]))),
+          relations.listenLine.slots({
+            context: [
+              'album',
+
+              (data.numTracks === 0
+                ? 'albumNoTracks'
+             : data.numTracks === 1
+                ? 'albumOneTrack'
+                : 'albumMultipleTracks'),
+            ],
           })),
       ])),
 };
diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js
index 070c7c82..0acf401c 100644
--- a/src/content/dependencies/generatePageLayout.js
+++ b/src/content/dependencies/generatePageLayout.js
@@ -583,6 +583,11 @@ export default {
           `    background-image: url("${to('media.path', 'bg.jpg')}");\n` +
           `}`);
 
+    const goshFrigginDarnitStyleRule =
+      `.image-media-link::after {\n` +
+      `    mask-image: url("${to('staticMisc.path', 'image.svg')}");\n` +
+      `}`;
+
     const numWallpaperParts =
       html.resolve(slots.styleRules, {normalize: 'string'})
         .match(/\.wallpaper-part:nth-child/g)
@@ -733,6 +738,7 @@ export default {
                 .slot('color', slots.color ?? data.wikiColor),
 
               fallbackBackgroundStyleRule,
+              goshFrigginDarnitStyleRule,
               slots.styleRules,
             ]),
 
diff --git a/src/content/dependencies/generateReleaseInfoListenLine.js b/src/content/dependencies/generateReleaseInfoListenLine.js
new file mode 100644
index 00000000..f2a6dd29
--- /dev/null
+++ b/src/content/dependencies/generateReleaseInfoListenLine.js
@@ -0,0 +1,150 @@
+import {isExternalLinkContext} from '#external-links';
+import {empty, stitchArrays, unique} from '#sugar';
+
+function getReleaseContext(urlString, {
+  _artistURLs,
+  albumArtistURLs,
+}) {
+  const composerBandcampDomains =
+    albumArtistURLs
+      .filter(url => url.hostname.endsWith('.bandcamp.com'))
+      .map(url => url.hostname);
+
+  const url = new URL(urlString);
+
+  if (url.hostname === 'homestuck.bandcamp.com') {
+    return 'officialRelease';
+  }
+
+  if (composerBandcampDomains.includes(url.hostname)) {
+    return 'composerRelease';
+  }
+
+  return null;
+}
+
+export default {
+  contentDependencies: ['linkExternal'],
+  extraDependencies: ['html', 'language'],
+
+  query(thing) {
+    const query = {};
+
+    query.album =
+      (thing.album
+        ? thing.album
+        : thing);
+
+    query.artists =
+      thing.artistContribs
+        .map(contrib => contrib.artist);
+
+    query.artistGroups =
+      query.artists
+        .flatMap(artist => artist.closelyLinkedGroups)
+        .map(({group}) => group);
+
+    query.albumArtists =
+      query.album.artistContribs
+        .map(contrib => contrib.artist);
+
+    query.albumArtistGroups =
+      query.albumArtists
+        .flatMap(artist => artist.closelyLinkedGroups)
+        .map(({group}) => group);
+
+    return query;
+  },
+
+  relations: (relation, _query, thing) => ({
+    links:
+      thing.urls.map(url => relation('linkExternal', url)),
+  }),
+
+  data(query, thing) {
+    const data = {};
+
+    data.name = thing.name;
+
+    const artistURLs =
+      unique([
+        ...query.artists.flatMap(artist => artist.urls),
+        ...query.artistGroups.flatMap(group => group.urls),
+      ]).map(url => new URL(url));
+
+    const albumArtistURLs =
+      unique([
+        ...query.albumArtists.flatMap(artist => artist.urls),
+        ...query.albumArtistGroups.flatMap(group => group.urls),
+      ]).map(url => new URL(url));
+
+    const boundGetReleaseContext = urlString =>
+      getReleaseContext(urlString, {
+        artistURLs,
+        albumArtistURLs,
+      });
+
+    let releaseContexts =
+      thing.urls.map(boundGetReleaseContext);
+
+    const albumReleaseContexts =
+      query.album.urls.map(boundGetReleaseContext);
+
+    const presentReleaseContexts =
+      unique(releaseContexts.filter(Boolean));
+
+    const presentAlbumReleaseContexts =
+      unique(albumReleaseContexts.filter(Boolean));
+
+    if (
+      presentReleaseContexts.length <= 1 &&
+      presentAlbumReleaseContexts.length <= 1
+    ) {
+      releaseContexts =
+        thing.urls.map(() => null);
+    }
+
+    data.releaseContexts = releaseContexts;
+
+    return data;
+  },
+
+  slots: {
+    visibleWithoutLinks: {
+      type: 'boolean',
+      default: false,
+    },
+
+    context: {
+      validate: () => isExternalLinkContext,
+      default: 'generic',
+    },
+  },
+
+  generate: (data, relations, slots, {html, language}) =>
+    language.encapsulate('releaseInfo.listenOn', capsule =>
+      (empty(relations.links) && slots.visibleWithoutLinks
+        ? language.$(capsule, 'noLinks', {
+            name:
+              html.tag('i', data.name),
+          })
+
+        : language.$('releaseInfo.listenOn', {
+            [language.onlyIfOptions]: ['links'],
+
+            links:
+              language.formatDisjunctionList(
+                stitchArrays({
+                  link: relations.links,
+                  releaseContext: data.releaseContexts,
+                }).map(({link, releaseContext}) =>
+                    link.slot('context', [
+                      ...
+                      (Array.isArray(slots.context)
+                        ? slots.context
+                        : [slots.context]),
+
+                      releaseContext,
+                    ]))),
+          }))),
+};
diff --git a/src/content/dependencies/generateTrackInfoPage.js b/src/content/dependencies/generateTrackInfoPage.js
index ca6f82b9..11d179ad 100644
--- a/src/content/dependencies/generateTrackInfoPage.js
+++ b/src/content/dependencies/generateTrackInfoPage.js
@@ -311,18 +311,6 @@ export default {
 
           relations.lyricsSection,
 
-          // html.tags([
-          //   relations.contentHeading.clone()
-          //     .slots({
-          //       attributes: {id: 'lyrics'},
-          //       title: language.$('releaseInfo.lyrics'),
-          //     }),
-
-          //   html.tag('blockquote',
-          //     {[html.onlyIfContent]: true},
-          //     relations.lyrics.slot('mode', 'lyrics')),
-          // ]),
-
           html.tags([
             relations.contentHeading.clone()
               .slots({
diff --git a/src/content/dependencies/generateTrackReleaseInfo.js b/src/content/dependencies/generateTrackReleaseInfo.js
index 54e462c7..3298dcc4 100644
--- a/src/content/dependencies/generateTrackReleaseInfo.js
+++ b/src/content/dependencies/generateTrackReleaseInfo.js
@@ -1,9 +1,7 @@
-import {empty} from '#sugar';
-
 export default {
   contentDependencies: [
     'generateReleaseInfoContributionsLine',
-    'linkExternal',
+    'generateReleaseInfoListenLine',
   ],
 
   extraDependencies: ['html', 'language'],
@@ -11,14 +9,11 @@ export default {
   relations(relation, track) {
     const relations = {};
 
-    relations.artistContributionLinks =
+    relations.artistContributionsLine =
       relation('generateReleaseInfoContributionsLine', track.artistContribs);
 
-    if (!empty(track.urls)) {
-      relations.externalLinks =
-        track.urls.map(url =>
-          relation('linkExternal', url));
-    }
+    relations.listenLine =
+      relation('generateReleaseInfoListenLine', track);
 
     return relations;
   },
@@ -48,7 +43,7 @@ export default {
           {[html.joinChildren]: html.tag('br')},
 
           [
-            relations.artistContributionLinks.slots({
+            relations.artistContributionsLine.slots({
               stringKey: capsule + '.by',
               featuringStringKey: capsule + '.by.featuring',
               chronologyKind: 'track',
@@ -66,17 +61,9 @@ export default {
           ]),
 
         html.tag('p',
-          language.encapsulate(capsule, 'listenOn', capsule =>
-            (relations.externalLinks
-              ? language.$(capsule, {
-                  links:
-                    language.formatDisjunctionList(
-                      relations.externalLinks
-                        .map(link => link.slot('context', 'track'))),
-                })
-              : language.$(capsule, 'noLinks', {
-                  name:
-                    html.tag('i', data.name),
-                })))),
+          relations.listenLine.slots({
+            visibleWithoutLinks: true,
+            context: ['track'],
+          })),
       ])),
 };
diff --git a/src/content/dependencies/listTracksWithLyrics.js b/src/content/dependencies/listTracksWithLyrics.js
index a13a76f0..e6ab9d7d 100644
--- a/src/content/dependencies/listTracksWithLyrics.js
+++ b/src/content/dependencies/listTracksWithLyrics.js
@@ -2,7 +2,7 @@ export default {
   contentDependencies: ['listTracksWithExtra'],
 
   relations: (relation, spec) =>
-    ({page: relation('listTracksWithExtra', spec, 'lyrics', 'truthy')}),
+    ({page: relation('listTracksWithExtra', spec, 'lyrics', 'array')}),
 
   generate: (relations) =>
     relations.page,
diff --git a/src/data/yaml.js b/src/data/yaml.js
index 50317238..af1d5740 100644
--- a/src/data/yaml.js
+++ b/src/data/yaml.js
@@ -1781,14 +1781,16 @@ export function flattenThingLayoutToDocumentOrder(layout) {
 }
 
 export function* splitDocumentsInYAMLSourceText(sourceText) {
-  const dividerRegex = /^-{3,}\n?/gm;
+  // Not multiline!
+  const dividerRegex = /(?:\r\n|\n|^)-{3,}(?:\r\n|\n|$)/g;
+
   let previousDivider = '';
 
   while (true) {
     const {lastIndex} = dividerRegex;
     const match = dividerRegex.exec(sourceText);
     if (match) {
-      const nextDivider = match[0].trim();
+      const nextDivider = match[0];
 
       yield {
         previousDivider,
@@ -1799,11 +1801,12 @@ export function* splitDocumentsInYAMLSourceText(sourceText) {
       previousDivider = nextDivider;
     } else {
       const nextDivider = '';
+      const lineBreak = previousDivider.match(/\r?\n/)?.[0] ?? '';
 
       yield {
         previousDivider,
         nextDivider,
-        text: sourceText.slice(lastIndex).replace(/(?<!\n)$/, '\n'),
+        text: sourceText.slice(lastIndex).replace(/(?<!\n)$/, lineBreak),
       };
 
       return;
@@ -1829,7 +1832,7 @@ export function recombineDocumentsIntoYAMLSourceText(documents) {
 
   for (const document of documents) {
     if (sourceText) {
-      sourceText += divider + '\n';
+      sourceText += divider;
     }
 
     sourceText += document.text;
diff --git a/src/external-links.js b/src/external-links.js
index 1055a391..daf57b41 100644
--- a/src/external-links.js
+++ b/src/external-links.js
@@ -32,6 +32,9 @@ export const externalLinkContexts = [
   'generic',
   'group',
   'track',
+
+  'composerRelease',
+  'officialRelease',
 ];
 
 export const isExternalLinkContext =
@@ -257,6 +260,30 @@ export const externalLinkSpec = [
   },
 
   {
+    match: {
+      domain: '.bandcamp.com',
+      context: 'composerRelease',
+    },
+
+    platform: 'bandcamp.composerRelease',
+    handle: {domain: /^[^.]+/},
+
+    icon: 'bandcamp',
+  },
+
+  {
+    match: {
+      domain: '.bandcamp.com',
+      context: 'officialRelease',
+    },
+
+    platform: 'bandcamp.officialRelease',
+    handle: {domain: /^[^.]+/},
+
+    icon: 'bandcamp',
+  },
+
+  {
     match: {domain: '.bandcamp.com'},
 
     platform: 'bandcamp',
diff --git a/src/static/css/site.css b/src/static/css/site.css
index 25d9ce47..8c53f877 100644
--- a/src/static/css/site.css
+++ b/src/static/css/site.css
@@ -931,7 +931,11 @@ a .normal-content {
 
   background-color: var(--primary-color);
 
-  mask-image: url(/static-4p1/misc/image.svg);
+  /* mask-image is set in content JavaScript,
+   * because we can't identify the correct nor
+   * absolute path to the file from CSS.
+   */
+
   mask-repeat: no-repeat;
   mask-position: calc(100% - 2px);
   vertical-align: text-bottom;
@@ -1119,7 +1123,7 @@ a .normal-content {
   font-size: 0.9rem;
 }
 
-li:not(:first-child:last-child) .tooltip,
+li:not(:first-child:last-child) .tooltip:where(:not(.cover-artwork .tooltip)),
 .offset-tooltips > :not(:first-child:last-child) .tooltip {
   left: 14px;
 }
@@ -1161,7 +1165,7 @@ li:not(:first-child:last-child) .tooltip,
 .thing-name-tooltip,
 .wiki-edits-tooltip {
   padding: 3px 4px 2px 2px;
-  left: -6px !important;
+  left: -6px;
 }
 
 .thing-name-tooltip .tooltip-content,
@@ -1169,11 +1173,15 @@ li:not(:first-child:last-child) .tooltip,
   font-size: 0.85em;
 }
 
-/* Terrifying?
- * https://stackoverflow.com/a/64424759/4633828
- */
-.thing-name-tooltip { margin-right: -120px; }
-.wiki-edits-tooltip { margin-right: -200px; }
+.thing-name-tooltip .tooltip-content {
+  width: max-content;
+  max-width: 120px;
+}
+
+.wiki-edits-tooltip .tooltip-content {
+  width: max-content;
+  max-width: 200px;
+}
 
 .contribution-tooltip .tooltip-content {
   padding: 6px 2px 2px 2px;
diff --git a/src/static/js/client/index.js b/src/static/js/client/index.js
index b2343f07..81ea3415 100644
--- a/src/static/js/client/index.js
+++ b/src/static/js/client/index.js
@@ -15,7 +15,6 @@ import * as hoverableTooltipModule from './hoverable-tooltip.js';
 import * as imageOverlayModule from './image-overlay.js';
 import * as intrapageDotSwitcherModule from './intrapage-dot-switcher.js';
 import * as liveMousePositionModule from './live-mouse-position.js';
-import * as lyricsSwitcherModule from './lyrics-switcher.js';
 import * as quickDescriptionModule from './quick-description.js';
 import * as scriptedLinkModule from './scripted-link.js';
 import * as sidebarSearchModule from './sidebar-search.js';
@@ -38,7 +37,6 @@ export const modules = [
   imageOverlayModule,
   intrapageDotSwitcherModule,
   liveMousePositionModule,
-  lyricsSwitcherModule,
   quickDescriptionModule,
   scriptedLinkModule,
   sidebarSearchModule,
diff --git a/src/static/js/client/lyrics-switcher.js b/src/static/js/client/lyrics-switcher.js
deleted file mode 100644
index b350ea50..00000000
--- a/src/static/js/client/lyrics-switcher.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/* eslint-env browser */
-
-import {stitchArrays} from '../../shared-util/sugar.js';
-
-import {cssProp} from '../client-util.js';
-
-export const info = {
-  id: 'lyricsSwitcherInfo',
-
-  entries: null,
-  switchLinks: null,
-  currentLinks: null,
-};
-
-export function getPageReferences() {
-  const content = document.getElementById('content');
-
-  if (!content) return;
-
-  const switcher = content.querySelector('.lyrics-switcher');
-
-  if (!switcher) return;
-
-  info.entries =
-    Array.from(content.querySelectorAll('.lyrics-entry'));
-
-  info.currentLinks =
-    Array.from(switcher.querySelectorAll('a.current'));
-
-  info.switchLinks =
-    Array.from(switcher.querySelectorAll('a:not(.current)'));
-}
-
-export function addPageListeners() {
-  if (!info.switchLinks) return;
-
-  for (const {switchLink, entry} of stitchArrays({
-    switchLink: info.switchLinks,
-    entry: info.entries,
-  })) {
-    switchLink.addEventListener('click', domEvent => {
-      domEvent.preventDefault();
-      showLyricsEntry(entry);
-    });
-  }
-}
-
-function showLyricsEntry(entry) {
-  const entryToShow = entry;
-
-  stitchArrays({
-    entry: info.entries,
-    currentLink: info.currentLinks,
-    switchLink: info.switchLinks,
-  }).forEach(({
-      entry,
-      currentLink,
-      switchLink,
-    }) => {
-      if (entry === entryToShow) {
-        cssProp(entry, 'display', null);
-        cssProp(currentLink, 'display', null);
-        cssProp(switchLink, 'display', 'none');
-      } else {
-        cssProp(entry, 'display', 'none');
-        cssProp(currentLink, 'display', 'none');
-        cssProp(switchLink, 'display', null);
-      }
-    });
-}
diff --git a/src/static/js/rectangles.js b/src/static/js/rectangles.js
index cdab2cb8..b00ed98e 100644
--- a/src/static/js/rectangles.js
+++ b/src/static/js/rectangles.js
@@ -510,4 +510,46 @@ export class WikiRect extends DOMRect {
       height: this.height,
     });
   }
+
+  // Other utilities
+
+  #display = null;
+
+  display() {
+    if (!this.#display) {
+      this.#display = document.createElement('div');
+      document.body.appendChild(this.#display);
+    }
+
+    Object.assign(this.#display.style, {
+      position: 'fixed',
+      background: '#000c',
+      border: '3px solid var(--primary-color)',
+      borderRadius: '4px',
+      top: this.top + 'px',
+      left: this.left + 'px',
+      width: this.width + 'px',
+      height: this.height + 'px',
+      pointerEvents: 'none',
+    });
+
+    let i = 0;
+    const int = setInterval(() => {
+      i++;
+      if (i >= 3) clearInterval(int);
+      if (!this.#display) return;
+
+      this.#display.style.display = 'none';
+      setTimeout(() => {
+        this.#display.style.display = '';
+      }, 200);
+    }, 600);
+  }
+
+  hide() {
+    if (this.#display) {
+      this.#display.remove();
+      this.#display = null;
+    }
+  }
 }
diff --git a/src/strings-default.yaml b/src/strings-default.yaml
index 7a40bd0d..6b68cdb6 100644
--- a/src/strings-default.yaml
+++ b/src/strings-default.yaml
@@ -647,7 +647,12 @@ misc:
     amazonMusic: "Amazon Music"
     appleMusic: "Apple Music"
     artstation: "ArtStation"
-    bandcamp: "Bandcamp"
+
+    bandcamp:
+      _: "Bandcamp"
+
+      composerRelease: "Bandcamp (composer's release)"
+      officialRelease: "Bandcamp (official release)"
 
     bgreco:
       _: "bgreco.net"
diff --git a/src/urls-default.yaml b/src/urls-default.yaml
index c3bf89eb..7fcccae8 100644
--- a/src/urls-default.yaml
+++ b/src/urls-default.yaml
@@ -11,7 +11,7 @@ yamlAliases:
   # part of a build. This is so that multiple builds of a wiki can coexist
   # served from the same server / file system root: older builds' HTML files
   # refer to earlier values of STATIC_VERSION, avoiding name collisions.
-  - &staticVersion 4p1
+  - &staticVersion 5r2
 
 data:
   prefix: 'data/'
diff --git a/src/write/build-modes/static-build.js b/src/write/build-modes/static-build.js
index 2baed816..3b69b066 100644
--- a/src/write/build-modes/static-build.js
+++ b/src/write/build-modes/static-build.js
@@ -4,6 +4,7 @@ import {
   copyFile,
   cp,
   mkdir,
+  readFile,
   stat,
   symlink,
   writeFile,
@@ -95,6 +96,11 @@ export function getCLIOptions() {
       type: 'value',
     },
 
+    'paths': {
+      help: `Skip rest and build only pages matching paths in this text file`,
+      type: 'value',
+    },
+
     // NOT for neatly ena8ling or disa8ling specific features of the site!
     // This is only in charge of what general groups of files to write.
     // They're here to make development quicker when you're only working
@@ -128,6 +134,7 @@ export async function go({
   const outputPath = cliOptions['out-path'] || process.env.HSMUSIC_OUT;
   const appendIndexHTML = cliOptions['append-index-html'] ?? false;
   const writeOneLanguage = cliOptions['lang'] ?? null;
+  const pathsFromFile = cliOptions['paths'] ?? null;
 
   if (!outputPath) {
     logError`Expected ${'--out-path'} option or ${'HSMUSIC_OUT'} to be set`;
@@ -147,6 +154,36 @@ export async function go({
     logInfo`Writing all languages.`;
   }
 
+  let filterPaths = null;
+  if (pathsFromFile) {
+    let pathsText;
+    try {
+      pathsText = await readFile(pathsFromFile, 'utf8');
+    } catch (error) {
+      logError`Failed to read file specified in ${'--paths'}:`;
+      logError`${error.code}: ${pathsFromFile}`;
+      return false;
+    }
+
+    filterPaths = pathsText.split('\n').filter(Boolean);
+
+    if (empty(filterPaths)) {
+      logWarn`Specified to build only paths in file ${'--paths'}:`;
+      logWarn`${pathsFromFile}`;
+      logWarn`But this file is totally empty...`;
+    }
+
+    if (filterPaths.some(path => !path.startsWith('/'))) {
+      logError`All lines in ${'--paths'} file should start with slash ('${'/'}')`;
+      logError`These lines don't:`;
+      console.error(filterPaths.filter(path => !path.startsWith('/')).join('\n'));
+      logError`Please check file contents, or specified path, and try again.`;
+      return false;
+    }
+
+    logInfo`Writing ${filterPaths.length} paths specified in: ${pathsFromFile} (${'--paths'})`;
+  }
+
   const selectedPageFlags = Object.keys(cliOptions)
     .filter(key => pageFlags.includes(key));
 
@@ -225,6 +262,27 @@ export async function go({
           // TODO: Validate each pathsForTargets entry
         }
 
+        if (!empty(filterPaths)) {
+          paths =
+            paths.filter(path =>
+              filterPaths.includes(
+                (path.type === 'page'
+                  ? '/' +
+                    getPagePathname({
+                      baseDirectory: '',
+                      pagePath: path.path,
+                      urls,
+                    })
+               : path.type === 'redirect'
+                  ? '/' +
+                    getPagePathname({
+                      baseDirectory: '',
+                      pagePath: path.fromPath,
+                      urls,
+                    })
+                  : null)));
+        }
+
         paths =
           paths.filter(path => path.condition?.() ?? true);