« 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:
-rwxr-xr-xupd8.js644
1 files changed, 339 insertions, 305 deletions
diff --git a/upd8.js b/upd8.js
index e17005dd..4ac3ab41 100755
--- a/upd8.js
+++ b/upd8.js
@@ -2338,8 +2338,8 @@ function validateWriteObject(obj) {
     return {success: true};
 }
 
-async function writeData(subKey, directory, data) {
-    const paths = writePage.paths('', 'data.' + subKey, directory, {file: 'data.json'});
+async function writeData(subKey, directory, file, data) {
+    const paths = writePage.paths('', 'data.' + subKey, directory, {file});
     await writePage.write(JSON.stringify(data), {paths});
 }
 
@@ -2975,10 +2975,12 @@ function writeNewsIndex() {
                         <article id="${entry.directory}">
                             <h2><time>${strings.count.date(entry.date)}</time> ${strings.link.newsEntry(entry, {to})}</h2>
                             ${transformMultiline(entry.bodyShort, {strings, to})}
-                            ${entry.bodyShort !== entry.body && `<p>${strings.link.newsEntry(entry, {
-                                to,
-                                text: strings('newsIndex.entry.viewRest')
-                            })}</p>`}
+                            ${entry.bodyShort !== entry.body && fixWS`
+                                <p>${strings.link.newsEntry(entry, {
+                                    to,
+                                    text: strings('newsIndex.entry.viewRest')
+                                })}</p>
+                            `}
                         </article>
                     `).join('\n')}
                 </div>
@@ -3120,18 +3122,19 @@ function writeAlbumPage(album) {
             duration: strings.count.duration(track.duration),
             track: strings.link.track(track, {to})
         };
-        return `<li style="${getLinkThemeString(track)}">${
-            (track.artists === album.artists
-                ? strings('trackList.item.withDuration', itemOpts)
-                : strings('trackList.item.withDuration.withArtists', {
-                    ...itemOpts,
-                    by: `<span class="by">${
-                        strings('trackList.item.withArtists.by', {
-                            artists: getArtistString(track.artists, {strings, to})
-                        })
-                    }</span>`
-                }))
-        }</li>`;
+
+        const content = (track.artists === album.artists
+            ? strings('trackList.item.withDuration', itemOpts)
+            : strings('trackList.item.withDuration.withArtists', {
+                ...itemOpts,
+                by: html.tag('span', {class: 'by'},
+                    strings('trackList.item.withArtists.by', {
+                        artists: getArtistString(track.artists, {strings, to})
+                    })
+                )
+            }));
+
+        return `<li style="${getLinkThemeString(track)}">${content}</li>`;
     };
 
     const commentaryEntries = [album, ...album.tracks].filter(x => x.commentary).length;
@@ -3185,100 +3188,108 @@ function writeAlbumPage(album) {
         },
 
         main: {
-            content: fixWS`
-                ${generateCoverLink({
-                    strings, to,
-                    src: to('media.albumCover', album.directory),
-                    alt: strings('misc.alt.albumCover'),
-                    tags: album.artTags
-                })}
-                <h1>${strings('albumPage.title', {album: album.name})}</h1>
-                <p>
-                    ${[
-                        album.artists && strings('releaseInfo.by', {
-                            artists: getArtistString(album.artists, {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })
-                        }),
-                        album.coverArtists && strings('releaseInfo.coverArtBy', {
-                            artists: getArtistString(album.coverArtists, {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })
-                        }),
-                        album.wallpaperArtists && strings('releaseInfo.wallpaperArtBy', {
-                            artists: getArtistString(album.wallpaperArtists, {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })
-                        }),
-                        album.bannerArtists && strings('releaseInfo.bannerArtBy', {
-                            artists: getArtistString(album.bannerArtists, {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })
-                        }),
-                        strings('releaseInfo.released', {
-                            date: strings.count.date(album.date)
-                        }),
-                        +album.coverArtDate !== +album.date && strings('releaseInfo.artReleased', {
-                            date: strings.count.date(album.coverArtDate)
-                        }),
-                        strings('releaseInfo.duration', {
-                            duration: strings.count.duration(albumDuration, {approximate: album.tracks.length > 1})
+            content: call(() => {
+                const releaseInfoParts = [
+                    album.artists && strings('releaseInfo.by', {
+                        artists: getArtistString(album.artists, {
+                            strings, to,
+                            showContrib: true,
+                            showIcons: true
                         })
-                    ].filter(Boolean).join('<br>\n')}
-                </p>
-                ${commentaryEntries && `<p>${
-                    strings('releaseInfo.viewCommentary', {
-                        link: `<a href="${to('localized.albumCommentary', album.directory)}">${
-                            strings('releaseInfo.viewCommentary.link')
-                        }</a>`
-                    })
-                }</p>`}
-                ${album.urls.length && `<p>${
-                    strings('releaseInfo.listenOn', {
-                        links: strings.list.or(album.urls.map(url => fancifyURL(url, {album: true, strings})))
+                    }),
+                    album.coverArtists && strings('releaseInfo.coverArtBy', {
+                        artists: getArtistString(album.coverArtists, {
+                            strings, to,
+                            showContrib: true,
+                            showIcons: true
+                        })
+                    }),
+                    album.wallpaperArtists && strings('releaseInfo.wallpaperArtBy', {
+                        artists: getArtistString(album.wallpaperArtists, {
+                            strings, to,
+                            showContrib: true,
+                            showIcons: true
+                        })
+                    }),
+                    album.bannerArtists && strings('releaseInfo.bannerArtBy', {
+                        artists: getArtistString(album.bannerArtists, {
+                            strings, to,
+                            showContrib: true,
+                            showIcons: true
+                        })
+                    }),
+                    strings('releaseInfo.released', {
+                        date: strings.count.date(album.date)
+                    }),
+                    +album.coverArtDate !== +album.date && strings('releaseInfo.artReleased', {
+                        date: strings.count.date(album.coverArtDate)
+                    }),
+                    strings('releaseInfo.duration', {
+                        duration: strings.count.duration(albumDuration, {approximate: album.tracks.length > 1})
                     })
-                }</p>`}
-                ${album.trackGroups ? fixWS`
-                    <dl class="album-group-list">
-                        ${album.trackGroups.map(({ name, color, startIndex, tracks }) => fixWS`
-                            <dt>${
-                                strings('trackList.group', {
-                                    duration: strings.count.duration(getTotalDuration(tracks), {approximate: tracks.length > 1}),
-                                    group: name
-                                })
-                            }</dt>
-                            <dd><${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}>
-                                ${tracks.map(t => trackToListItem(t, {strings, to})).join('\n')}
-                            </${listTag}></dd>
-                        `).join('\n')}
-                    </dl>
-                ` : fixWS`
-                    <${listTag}>
-                        ${album.tracks.map(t => trackToListItem(t, {strings, to})).join('\n')}
-                    </${listTag}>
-                `}
-                <p>
-                    ${[
+                ].filter(Boolean);
+
+                const trackListPart = (album.trackGroups
+                    ? html.tag('dl', {class: 'album-group-list'},
+                        album.trackGroups.map(({ name, color, startIndex, tracks }) => {
+                            const label = strings('trackList.group', {
+                                duration: strings.count.duration(getTotalDuration(tracks), {approximate: tracks.length > 1}),
+                                group: name
+                            });
+                            return fixWS`
+                                <dt>${label}</dt>
+                                <dd><${listTag === 'ol' ? `ol start="${startIndex + 1}"` : listTag}>
+                                    ${tracks.map(t => trackToListItem(t, {strings, to})).join('\n')}
+                                </${listTag}></dd>
+                            `;
+                        })
+                    )
+                    : fixWS`
+                        <${listTag}>
+                            ${album.tracks.map(t => trackToListItem(t, {strings, to})).join('\n')}
+                        </${listTag}>
+                    `);
+
+                return [
+                    generateCoverLink({
+                        strings, to,
+                        src: to('media.albumCover', album.directory),
+                        alt: strings('misc.alt.albumCover'),
+                        tags: album.artTags
+                    }),
+
+                    `<h1>${strings('albumPage.title', {album: album.name})}</h1>`,
+
+                    html.tag('p', releaseInfoParts.join('<br>\n')),
+
+                    commentaryEntries && html.tag('p',
+                        strings('releaseInfo.viewCommentary', {
+                            link: `<a href="${to('localized.albumCommentary', album.directory)}">${
+                                strings('releaseInfo.viewCommentary.link')
+                            }</a>`
+                        })
+                    ),
+
+                    album.urls.length && html.tag('p',
+                        strings('releaseInfo.listenOn', {
+                            links: strings.list.or(album.urls.map(url => fancifyURL(url, {album: true, strings})))
+                        })
+                    ),
+
+                    trackListPart,
+
+                    html.tag('p', [
                         strings('releaseInfo.addedToWiki', {
                             date: strings.count.date(album.dateAdded)
                         })
-                    ].filter(Boolean).join('<br>\n')}
-                </p>
-                ${album.commentary && fixWS`
-                    <p>${strings('releaseInfo.artistCommentary')}</p>
-                    <blockquote>
-                        ${transformMultiline(album.commentary, {strings, to})}
-                    </blockquote>
-                `}
-            `
+                    ].filter(Boolean).join('<br>\n')),
+
+                    album.commentary && fixWS`
+                        <p>${strings('releaseInfo.artistCommentary')}</p>
+                        ${html.tag('blockquote', transformMultiline(album.commentary, {strings, to}))}
+                    `
+                ].filter(Boolean).join('\n');
+            })
         },
 
         sidebarLeft: generateSidebarForAlbum(album, null, {strings, to}),
@@ -3428,103 +3439,114 @@ function writeTrackPage(track) {
         */
 
         main: {
-            content: fixWS`
-                ${generateCoverLink({
-                    strings, to,
-                    src: getTrackCover(track, {to}),
-                    alt: strings('misc.alt.trackCover'),
-                    tags: track.artTags
-                })}
-                <h1>${strings('trackPage.title', {track: track.name})}</h1>
-                <p>
-                    ${[
-                        strings('releaseInfo.by', {
-                            artists: getArtistString(track.artists, {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })
-                        }),
-                        track.coverArtists && strings('releaseInfo.coverArtBy', {
-                            artists: getArtistString(track.coverArtists, {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })
-                        }),
-                        album.directory !== C.UNRELEASED_TRACKS_DIRECTORY && strings('releaseInfo.released', {
-                            date: strings.count.date(track.date)
-                        }),
-                        +track.coverArtDate !== +track.date && strings('releaseInfo.artReleased', {
-                            date: strings.count.date(track.coverArtDate)
-                        }),
-                        track.duration && strings('releaseInfo.duration', {
-                            duration: strings.count.duration(track.duration)
+            content: call(() => {
+                const releaseInfoParts = [
+                    strings('releaseInfo.by', {
+                        artists: getArtistString(track.artists, {
+                            strings, to,
+                            showContrib: true,
+                            showIcons: true
                         })
-                    ].filter(Boolean).join('<br>\n')}
-                </p>
-                <p>${
-                    (track.urls.length
-                        ? strings('releaseInfo.listenOn', {
-                            links: strings.list.or(track.urls.map(url => fancifyURL(url, {strings})))
+                    }),
+                    track.coverArtists && strings('releaseInfo.coverArtBy', {
+                        artists: getArtistString(track.coverArtists, {
+                            strings, to,
+                            showContrib: true,
+                            showIcons: true
                         })
-                        : strings('releaseInfo.listenOn.noLinks'))
-                }</p>
-                ${otherReleases.length && fixWS`
-                    <p>${strings('releaseInfo.alsoReleasedAs')}</p>
-                    <ul>
-                        ${otherReleases.map(track => fixWS`
-                            <li>${strings('releaseInfo.alsoReleasedAs.item', {
-                                track: strings.link.track(track, {to}),
-                                album: strings.link.album(track.album, {to})
-                            })}</li>
-                        `).join('\n')}
-                    </ul>
-                `}
-                ${track.contributors.textContent && fixWS`
-                    <p>
-                        ${strings('releaseInfo.contributors')}
-                        <br>
-                        ${transformInline(track.contributors.textContent, {strings, to})}
-                    </p>
-                `}
-                ${track.contributors.length && fixWS`
-                    <p>${strings('releaseInfo.contributors')}</p>
-                    <ul>
-                        ${(track.contributors
-                            .map(contrib => `<li>${getArtistString([contrib], {
-                                strings, to,
-                                showContrib: true,
-                                showIcons: true
-                            })}</li>`)
-                            .join('\n'))}
-                    </ul>
-                `}
-                ${tracksReferenced.length && fixWS`
-                    <p>${strings('releaseInfo.tracksReferenced', {track: `<i>${track.name}</i>`})}</p>
-                    ${generateTrackList(tracksReferenced, {strings, to})}
-                `}
-                ${tracksThatReference.length && fixWS`
-                    <p>${strings('releaseInfo.tracksThatReference', {track: `<i>${track.name}</i>`})}</p>
-                    ${useDividedReferences && fixWS`
-                        <dl>
-                            ${ttrOfficial.length && fixWS`
-                                <dt>${strings('trackPage.referenceList.official')}</dt>
-                                <dd>${generateTrackList(ttrOfficial, {strings, to})}</dd>
-                            `}
-                            ${ttrFanon.length && fixWS`
-                                <dt>${strings('trackPage.referenceList.fandom')}</dt>
-                                <dd>${generateTrackList(ttrFanon, {strings, to})}</dd>
-                            `}
-                        </dl>
-                    `}
-                    ${!useDividedReferences && generateTrackList(tracksThatReference, {strings, to})}
-                `}
-                ${wikiInfo.features.flashesAndGames && flashesThatFeature.length && fixWS`
-                    <p>${strings('releaseInfo.flashesThatFeature', {track: `<i>${track.name}</i>`})}</p>
-                    <ul>
-                        ${flashesThatFeature.map(({ flash, as }) => fixWS`
-                            <li ${classes(as !== track && 'rerelease')}>${
+                    }),
+                    album.directory !== C.UNRELEASED_TRACKS_DIRECTORY && strings('releaseInfo.released', {
+                        date: strings.count.date(track.date)
+                    }),
+                    +track.coverArtDate !== +track.date && strings('releaseInfo.artReleased', {
+                        date: strings.count.date(track.coverArtDate)
+                    }),
+                    track.duration && strings('releaseInfo.duration', {
+                        duration: strings.count.duration(track.duration)
+                    })
+                ].filter(Boolean);
+
+                return [
+                    generateCoverLink({
+                        strings, to,
+                        src: getTrackCover(track, {to}),
+                        alt: strings('misc.alt.trackCover'),
+                        tags: track.artTags
+                    }),
+
+                    `<h1>${strings('trackPage.title', {track: track.name})}</h1>`,
+
+                    html.tag('p', releaseInfoParts.join('<br>\n')),
+
+                    html.tag('p',
+                        (track.urls.length
+                            ? strings('releaseInfo.listenOn', {
+                                links: strings.list.or(track.urls.map(url => fancifyURL(url, {strings})))
+                            })
+                            : strings('releaseInfo.listenOn.noLinks'))
+                    ),
+
+                    otherReleases.length && fixWS`
+                        <p>${strings('releaseInfo.alsoReleasedAs')}</p>
+                        ${html.tag('ul',
+                            otherReleases.map(track => fixWS`
+                                <li>${strings('releaseInfo.alsoReleasedAs.item', {
+                                    track: strings.link.track(track, {to}),
+                                    album: strings.link.album(track.album, {to})
+                                })}</li>
+                            `)
+                        )}
+                    `,
+
+                    track.contributors.textContent && html.tag('p', [
+                        strings('releaseInfo.contributors'),
+                        '<br>',
+                        transformInline(track.contributors.textContent, {strings, to})
+                    ]),
+
+                    track.contributors.length && fixWS`
+                        <p>${strings('releaseInfo.contributors')}</p>
+                        ${html.tag('p',
+                            track.contributors.map(contrib => html.tag('li',
+                                getArtistString([contrib], {
+                                    strings, to,
+                                    showContrib: true,
+                                    showIcons: true
+                                })
+                            ))
+                        )}
+                    `,
+
+                    ...tracksReferenced.length ? [
+                        html.tag('p', strings('releaseInfo.tracksReferenced', {
+                            track: `<i>${track.name}</i>`
+                        })),
+                        generateTrackList(tracksReferenced, {strings, to})
+                    ] : [],
+
+                    ...tracksThatReference.length ? [
+                        html.tag('p', strings('releaseInfo.tracksThatReference', {
+                            track: `<i>${track.name}</i>`
+                        })),
+                        (useDividedReferences
+                            ? html.tag('dl', [
+                                ...ttrOfficial.length ? [
+                                    `<dt>${strings('trackPage.referenceList.official')}</dt>`,
+                                    `<dd>${generateTrackList(ttrOfficial, {strings, to})}</dd>`
+                                ] : [],
+                                ...ttrFanon.length ? [
+                                    `<dt>${strings('trackPage.referenceList.fandom')}</dt>`,
+                                    `<dd>${generateTrackList(ttrFanon, {strings, to})}</dd>`
+                                ] : []
+                            ])
+                            : generateTrackList(tracksThatReference, {strings, to}))
+                    ] : [],
+
+                    ...wikiInfo.features.flashesAndGames && flashesThatFeature.length ? [
+                        `<p>${strings('releaseInfo.flashesThatFeature', {track: `<i>${track.name}</i>`})}</p>`,
+                        html.tag('ul',
+                            flashesThatFeature.map(({ flash, as }) => html.tag('li',
+                                {class: [as !== track && 'rerelease']},
                                 (as === track
                                     ? strings('releaseInfo.flashesThatFeature.item', {
                                         flash: strings.link.flash(flash, {to})
@@ -3533,23 +3555,21 @@ function writeTrackPage(track) {
                                         flash: strings.link.flash(flash, {to}),
                                         track: strings.link.track(as, {to})
                                     }))
-                            }</li>
-                        `).join('\n')}
-                    </ul>
-                `}
-                ${track.lyrics && fixWS`
-                    <p>${strings('releaseInfo.lyrics')}</p>
-                    <blockquote>
-                        ${transformLyrics(track.lyrics, {strings, to})}
-                    </blockquote>
-                `}
-                ${hasCommentary && fixWS`
-                    <p>${strings('releaseInfo.artistCommentary')}</p>
-                    <blockquote>
-                        ${generateCommentary({strings, to})}
-                    </blockquote>
-                `}
-            `
+                            ))
+                        )
+                    ] : [],
+
+                    ...track.lyrics ? [
+                        `<p>${strings('releaseInfo.lyrics')}</p>`,
+                        html.tag('blockquote', transformLyrics(track.lyrics, {strings, to}))
+                    ] : [],
+
+                    ...hasCommentary ? [
+                        `<p>${strings('releaseInfo.artistCommentary')}</p>`,
+                        html.tag('blockquote', generateCommentary({strings, to}))
+                    ] : []
+                ].filter(Boolean).join('\n');
+            })
         },
 
         sidebarLeft: generateSidebarForAlbum(album, track, {strings, to}),
@@ -3801,30 +3821,33 @@ function writeArtistPage(artist) {
             title: strings('artistPage.title', {artist: name}),
 
             main: {
-                content: fixWS`
-                    ${artist.hasAvatar && generateCoverLink({
+                content: [
+                    artist.hasAvatar && generateCoverLink({
                         strings, to,
                         src: to('localized.artistAvatar', artist.directory),
                         alt: strings('misc.alt.artistAvatar')
-                    })}
-                    <h1>${strings('artistPage.title', {artist: name})}</h1>
-                    ${note && fixWS`
-                        <p>${strings('releaseInfo.note')}</p>
-                        <blockquote>
-                            ${transformMultiline(note, {strings, to})}
-                        </blockquote>
-                        <hr>
-                    `}
-                    ${urls.length && `<p>${strings('releaseInfo.visitOn', {
+                    }),
+
+                    `<h1>${strings('artistPage.title', {artist: name})}</h1>`,
+
+                    ...note ? [
+                        `<p>${strings('releaseInfo.note')}</p>`,
+                        html.tag('blockquote', transformMultiline(note, {strings, to})),
+                        `<hr>`
+                    ],
+
+                    urls.length && html.tag('p', strings('releaseInfo.visitOn', {
                         links: strings.list.or(urls.map(url => fancifyURL(url, {strings})))
-                    })}</p>`}
-                    ${hasGallery && `<p>${strings('artistPage.viewArtGallery', {
+                    })),
+
+                    hasGallery && html.tag('p', strings('artistPage.viewArtGallery', {
                         link: strings.link.artistGallery(artist, {
                             to,
                             text: strings('artistPage.viewArtGallery.link')
                         })
-                    })}</p>`}
-                    <p>${strings('misc.jumpTo.withLinks', {
+                    })),
+
+                    html.tag('p', strings('misc.jumpTo.withLinks', {
                         links: strings.list.unit([
                             [
                                 [...releasedTracks, ...unreleasedTracks].length && `<a href="#tracks">${strings('artistPage.trackList.title')}</a>`,
@@ -3834,51 +3857,57 @@ function writeArtistPage(artist) {
                             wikiInfo.features.flashesAndGames && flashes.length && `<a href="#flashes">${strings('artistPage.flashList.title')}</a>`,
                             commentaryThings.length && `<a href="#commentary">${strings('artistPage.commentaryList.title')}</a>`
                         ].filter(Boolean))
-                    })}</p>
-                    ${(releasedTracks.length || unreleasedTracks.length) && fixWS`
-                        <h2 id="tracks">${strings('artistPage.trackList.title')}</h2>
-                    `}
-                    ${releasedTracks.length && fixWS`
-                        <p>${strings('artistPage.contributedDurationLine', {
+                    })),
+
+                    (releasedTracks.length || unreleasedTracks.length) && (
+                        `<h2 id="tracks">${strings('artistPage.trackList.title')}</h2>`),
+
+                    ...releasedTracks.length ? [
+                        html.tag('p', strings('artistPage.contributedDurationLine', {
                             artist: artist.name,
                             duration: strings.count.duration(totalReleasedDuration, {approximate: true, unit: true})
-                        })}</p>
-                        <p>${strings('artistPage.musicGroupsLine', {
+                        })),
+                        html.tag('p', strings('artistPage.musicGroupsLine', {
                             groups: strings.list.unit(musicGroups
                                 .map(({ group, contributions }) => strings('artistPage.groupsLine.item', {
                                     group: strings.link.groupInfo(group, {to}),
                                     contributions: strings.count.contributions(contributions)
                                 })))
-                        })}</p>
-                        ${generateTrackList(releasedTrackListChunks, {strings, to})}
-                    `}
-                    ${unreleasedTracks.length && fixWS`
-                        <h3 id="unreleased-tracks">${strings('artistPage.unreleasedTrackList.title')}</h3>
-                        ${generateTrackList(unreleasedTrackListChunks, {strings, to})}
-                    `}
-                    ${artThingsAll.length && fixWS`
-                        <h2 id="art">${strings('artistPage.artList.title')}</h2>
-                        ${hasGallery && `<p>${strings('artistPage.viewArtGallery.orBrowseList', {
+                        })),
+                        generateTrackList(releasedTrackListChunks, {strings, to})
+                    ] : [],
+
+                    ...unreleasedTracks.length ? [
+                        `<h3 id="unreleased-tracks">${strings('artistPage.unreleasedTrackList.title')}</h3>`,
+                        generateTrackList(unreleasedTrackListChunks, {strings, to})
+                    ] : [],
+
+                    ...artThingsAll.length ? [
+                        `<h2 id="art">${strings('artistPage.artList.title')}</h2>`,
+
+                        hasGallery && html.tag('p', strings('artistPage.viewArtGallery.orBrowseList', {
                             link: strings.link.artistGallery(artist, {
                                 to,
                                 text: strings('artistPage.viewArtGallery.link')
                             })
-                        })}</p>`}
-                        <p>${strings('artistPage.artGroupsLine', {
+                        })),
+
+                        html.tag('p', strings('artistPage.artGroupsLine', {
                             groups: strings.list.unit(artGroups
                                 .map(({ group, contributions }) => strings('artistPage.groupsLine.item', {
                                     group: strings.link.groupInfo(group, {to}),
                                     contributions: strings.count.contributions(contributions)
                                 })))
-                        })}</p>
-                        <dl>
-                            ${artListChunks.map(({date, album, chunk}) => fixWS`
-                                <dt>${strings('artistPage.creditList.album.withDate', {
+                        }))
+
+                        html.tag('dl',
+                            artListChunks.flatMap(({date, album, chunk}) => [
+                                html.tag('dt', strings('artistPage.creditList.album.withDate', {
                                     album: strings.link.album(album, {to}),
                                     date: strings.count.date(date)
-                                })}</dt>
-                                <dd><ul>
-                                    ${(chunk
+                                })),
+                                html.tag('dd', html.tag('ul',
+                                    (chunk
                                         .map(({album, track, key, ...props}) => ({
                                             entry: (track
                                                 ? strings('artistPage.creditList.entry.track', {
@@ -3893,21 +3922,22 @@ function writeArtistPage(artist) {
                                         }))
                                         .map(opts => generateEntryAccents({strings, to, ...opts}))
                                         .map(row => `<li>${row}</li>`)
-                                        .join('\n'))}
-                                </ul></dd>
-                            `).join('\n')}
-                        </dl>
-                    `}
-                    ${wikiInfo.features.flashesAndGames && flashes.length && fixWS`
-                        <h2 id="flashes">${strings('artistPage.flashList.title')}</h2>
-                        <dl>
-                            ${flashListChunks.map(({act, chunk, dateFirst, dateLast}) => fixWS`
-                                <dt>${strings('artistPage.creditList.flashAct.withDateRange', {
+                                        .join('\n'))
+                                ))
+                            ])
+                        )
+                    ] : [],
+
+                    ...wikiInfo.features.flashesAndGames && flashes.length ? [
+                        `<h2 id="flashes">${strings('artistPage.flashList.title')}</h2>`,
+                        html.tag('dl',
+                            flashListChunks.flatMap(({act, chunk, dateFirst, dateLast}) => [
+                                html.tag('dt', strings('artistPage.creditList.flashAct.withDateRange', {
                                     act: strings.link.flash(chunk[0].flash, {to, text: act.name}),
                                     dateRange: strings.count.dateRange([dateFirst, dateLast])
-                                })}</dt>
-                                <dd><ul>
-                                    ${(chunk
+                                })),
+                                html.tag('dd', html.tag('ul',
+                                    (chunk
                                         .map(({flash, ...props}) => ({
                                             entry: strings('artistPage.creditList.entry.flash', {
                                                 flash: strings.link.flash(flash, {to})
@@ -3916,32 +3946,33 @@ function writeArtistPage(artist) {
                                         }))
                                         .map(opts => generateEntryAccents({strings, to, ...opts}))
                                         .map(row => `<li>${row}</li>`)
-                                        .join('\n'))}
-                                </ul></dd>
-                            `).join('\n')}
-                        </dl>
-                    `}
-                    ${commentaryThings.length && fixWS`
-                        <h2 id="commentary">${strings('artistPage.commentaryList.title')}</h2>
-                        <dl>
-                            ${commentaryListChunks.map(({album, chunk}) => fixWS`
-                                <dt>${strings('artistPage.creditList.album', {
+                                        .join('\n'))
+                                ))
+                            ])
+                        )
+                    ] : [],
+
+                    ...commentaryThings.length ? [
+                        `<h2 id="commentary">${strings('artistPage.commentaryList.title')}</h2>`,
+                        html.tag('dl',
+                            commentaryListChunks.flatMap(({album, chunk}) => [
+                                html.tag('dt', strings('artistPage.creditList.album', {
                                     album: strings.link.album(album, {to})
-                                })}</dt>
-                                <dd><ul>
-                                    ${(chunk
+                                })),
+                                html.tag('dd', html.tag('ul',
+                                    (chunk
                                         .map(({album, track, ...props}) => track
                                             ? strings('artistPage.creditList.entry.track', {
                                                 track: strings.link.track(track, {to})
                                             })
                                             : `<i>${strings('artistPage.creditList.entry.album.commentary')}</i>`)
                                         .map(row => `<li>${row}</li>`)
-                                        .join('\n'))}
-                                </ul></dd>
-                            `).join('\n')}
-                        </dl>
-                    `}
-                `
+                                        .join('\n'))
+                                ))
+                            ])
+                        )
+                    ] : []
+                ].filter(Boolean).join('\n')
             },
 
             nav: generateNavForArtist(artist, {strings, to, isGallery: false, hasGallery})
@@ -3956,13 +3987,15 @@ function writeArtistPage(artist) {
 
             main: {
                 classes: ['top-index'],
-                content: fixWS`
-                    <h1>${strings('artistGalleryPage.title', {artist: name})}</h1>
-                    <p class="quick-info">${strings('artistGalleryPage.infoLine', {
-                        coverArts: strings.count.coverArts(artThingsGallery.length, {unit: true})
-                    })}</p>
-                    <div class="grid-listing">
-                        ${getGridHTML({
+                content: [
+                    `<h1>${strings('artistGalleryPage.title', {artist: name})}</h1>`,
+                    html.tag('p', {class: 'quick-info'},
+                        strings('artistGalleryPage.infoLine', {
+                            coverArts: strings.count.coverArts(artThingsGallery.length, {unit: true})
+                        })
+                    ),
+                    html.tag('div', {class: 'grid-listing'},
+                        getGridHTML({
                             strings, to,
                             entries: artThingsGallery.map(item => ({item})),
                             srcFn: thing => (thing.album
@@ -3971,9 +4004,9 @@ function writeArtistPage(artist) {
                             hrefFn: thing => (thing.album
                                 ? to('localized.track', thing.directory)
                                 : to('localized.album', thing.directory))
-                        })}
-                    </div>
-                `
+                        })
+                    )
+                ].filter(Boolean).join('\n')
             },
 
             nav: generateNavForArtist(artist, {strings, to, isGallery: true, hasGallery})
@@ -6561,7 +6594,8 @@ async function main() {
 
     await progressPromiseAll(`Writing data files shared across languages.`, queue(
         // TODO: This only supports one <>-style argument.
-        dataWrites.map(({path, data}) => () => writeData(path[0], path[1], data())),
+        dataWrites.map(({path, file = 'data.json', data}) =>
+            () => writeData(path[0], path[1], file, data())),
         queueSize
     ));