From c75b029160248b6935e5c0f5156cc7a870311e82 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Sun, 26 Jun 2022 18:02:27 -0300 Subject: real pragma, and some eslint fixes --- src/util/cli.js | 70 ++++++++++++++-------------- src/util/colors.js | 4 +- src/util/find.js | 62 ++++++++++++------------- src/util/html.js | 60 ++++++++++++------------ src/util/io.js | 10 ++-- src/util/link.js | 94 ++++++++++++++++++------------------- src/util/magic-constants.js | 8 ++-- src/util/node-utils.js | 10 ++-- src/util/replacer.js | 84 ++++++++++++++++----------------- src/util/serialize.js | 20 ++++---- src/util/sugar.js | 110 ++++++++++++++++++++++---------------------- src/util/urls.js | 36 +++++++-------- src/util/wiki-data.js | 84 ++++++++++++++++----------------- 13 files changed, 326 insertions(+), 326 deletions(-) (limited to 'src/util') diff --git a/src/util/cli.js b/src/util/cli.js index 159d526b..d28ef40a 100644 --- a/src/util/cli.js +++ b/src/util/cli.js @@ -1,17 +1,17 @@ -// @format -// +/** @format */ + // Utility functions for CLI- and de8ugging-rel8ted stuff. // // A 8unch of these depend on process.stdout 8eing availa8le, so they won't // work within the 8rowser. -const { process } = globalThis; +const {process} = globalThis; export const ENABLE_COLOR = process && - ((process.env.CLICOLOR_FORCE && process.env.CLICOLOR_FORCE === "1") ?? + ((process.env.CLICOLOR_FORCE && process.env.CLICOLOR_FORCE === '1') ?? (process.env.CLICOLOR && - process.env.CLICOLOR === "1" && + process.env.CLICOLOR === '1' && process.stdout.hasColors && process.stdout.hasColors()) ?? (process.stdout.hasColors ? process.stdout.hasColors() : true)); @@ -20,17 +20,17 @@ const C = (n) => ENABLE_COLOR ? (text) => `\x1b[${n}m${text}\x1b[0m` : (text) => text; export const color = { - bright: C("1"), - dim: C("2"), - normal: C("22"), - black: C("30"), - red: C("31"), - green: C("32"), - yellow: C("33"), - blue: C("34"), - magenta: C("35"), - cyan: C("36"), - white: C("37"), + bright: C('1'), + dim: C('2'), + normal: C('22'), + black: C('30'), + red: C('31'), + green: C('32'), + yellow: C('33'), + blue: C('34'), + magenta: C('35'), + cyan: C('36'), + white: C('37'), }; const logColor = @@ -51,7 +51,7 @@ const logColor = } } wc(`\x1b[0m`); - w("\n"); + w('\n'); }; export const logInfo = logColor(2); @@ -105,9 +105,9 @@ export async function parseOptions(options, optionDescriptorMap) { const result = Object.create(null); for (let i = 0; i < options.length; i++) { const option = options[i]; - if (option.startsWith("--")) { + if (option.startsWith('--')) { // --x can be a flag or expect a value or series of values - let name = option.slice(2).split("=")[0]; // '--x'.split('=') = ['--x'] + let name = option.slice(2).split('=')[0]; // '--x'.split('=') = ['--x'] let descriptor = optionDescriptorMap[name]; if (!descriptor) { if (handleUnknown) { @@ -122,13 +122,13 @@ export async function parseOptions(options, optionDescriptorMap) { name = descriptor.alias; descriptor = optionDescriptorMap[name]; } - if (descriptor.type === "flag") { + if (descriptor.type === 'flag') { result[name] = true; - } else if (descriptor.type === "value") { - let value = option.slice(2).split("=")[1]; + } else if (descriptor.type === 'value') { + let value = option.slice(2).split('=')[1]; if (!value) { value = options[++i]; - if (!value || value.startsWith("-")) { + if (!value || value.startsWith('-')) { value = null; } } @@ -137,14 +137,14 @@ export async function parseOptions(options, optionDescriptorMap) { process.exit(1); } result[name] = value; - } else if (descriptor.type === "series") { - if (!options.slice(i).includes(";")) { + } else if (descriptor.type === 'series') { + if (!options.slice(i).includes(';')) { console.error( `Expected a series of values concluding with ; (\\;) for --${name}` ); process.exit(1); } - const endIndex = i + options.slice(i).indexOf(";"); + const endIndex = i + options.slice(i).indexOf(';'); result[name] = options.slice(i + 1, endIndex); i = endIndex; } @@ -155,7 +155,7 @@ export async function parseOptions(options, optionDescriptorMap) { process.exit(1); } } - } else if (option.startsWith("-")) { + } else if (option.startsWith('-')) { // mtui doesn't use any -x=y or -x y format optionuments // -x will always just be a flag let name = option.slice(1); @@ -173,7 +173,7 @@ export async function parseOptions(options, optionDescriptorMap) { name = descriptor.alias; descriptor = optionDescriptorMap[name]; } - if (descriptor.type === "flag") { + if (descriptor.type === 'flag') { result[name] = true; } else { console.error(`Use --${name} (value) to specify ${name}`); @@ -191,7 +191,7 @@ export const handleUnknown = Symbol(); export function decorateTime(arg1, arg2) { const [id, functionToBeWrapped] = - typeof arg1 === "string" || typeof arg1 === "symbol" + typeof arg1 === 'string' || typeof arg1 === 'symbol' ? [arg1, arg2] : [Symbol(arg1.name), arg1]; @@ -202,7 +202,7 @@ export function decorateTime(arg1, arg2) { displayTime() { const averageTime = meta.timeSpent / meta.timesCalled; console.log( - `\x1b[1m${typeof id === "symbol" ? id.description : id}(...):\x1b[0m ${ + `\x1b[1m${typeof id === 'symbol' ? id.description : id}(...):\x1b[0m ${ meta.timeSpent } ms / ${meta.timesCalled} calls \x1b[2m(avg: ${averageTime} ms)\x1b[0m` ); @@ -236,7 +236,7 @@ decorateTime.displayTime = function () { ]; if (keys.length) { - console.log(`\x1b[1mdecorateTime results: ` + "-".repeat(40) + "\x1b[0m"); + console.log(`\x1b[1mdecorateTime results: ` + '-'.repeat(40) + '\x1b[0m'); for (const key of keys) { map[key].displayTime(); } @@ -249,7 +249,7 @@ export function progressPromiseAll(msgOrMsgFn, array) { } const msgFn = - typeof msgOrMsgFn === "function" ? msgOrMsgFn : () => msgOrMsgFn; + typeof msgOrMsgFn === 'function' ? msgOrMsgFn : () => msgOrMsgFn; let done = 0, total = array.length; @@ -260,9 +260,9 @@ export function progressPromiseAll(msgOrMsgFn, array) { Promise.resolve(promise).then((val) => { done++; // const pc = `${done}/${total}`; - const pc = (Math.round((done / total) * 1000) / 10 + "%").padEnd( - "99.9%".length, - " " + const pc = (Math.round((done / total) * 1000) / 10 + '%').padEnd( + '99.9%'.length, + ' ' ); if (done === total) { const time = Date.now() - start; diff --git a/src/util/colors.js b/src/util/colors.js index 8d6b24df..5848a820 100644 --- a/src/util/colors.js +++ b/src/util/colors.js @@ -1,5 +1,5 @@ -// @format -// +/** @format */ + // Color and theming utility functions! Handy. // Graciously stolen from https://stackoverflow.com/a/54071699! ::::) diff --git a/src/util/find.js b/src/util/find.js index 6ee0583c..460a4fad 100644 --- a/src/util/find.js +++ b/src/util/find.js @@ -1,14 +1,14 @@ -// @format +/** @format */ -import { color, logError, logWarn } from "./cli.js"; +import {color, logError, logWarn} from './cli.js'; -import { inspect } from "util"; +import {inspect} from 'util'; function warnOrThrow(mode, message) { switch (mode) { - case "error": + case 'error': throw new Error(message); - case "warn": + case 'warn': logWarn(message); default: return null; @@ -26,16 +26,16 @@ function findHelper(keys, findFns = {}) { const byName = findFns.byName || matchName; const keyRefRegex = new RegExp( - String.raw`^(?:(${keys.join("|")}):(?=\S))?(.*)$` + String.raw`^(?:(${keys.join('|')}):(?=\S))?(.*)$` ); // The mode argument here may be 'warn', 'error', or 'quiet'. 'error' throws // errors for null matches (with details about the error), while 'warn' and // 'quiet' both return null, with 'warn' logging details directly to the // console. - return (fullRef, data, { mode = "warn" } = {}) => { + return (fullRef, data, {mode = 'warn'} = {}) => { if (!fullRef) return null; - if (typeof fullRef !== "string") { + if (typeof fullRef !== 'string') { throw new Error( `Got a reference that is ${typeof fullRef}, not string: ${fullRef}` ); @@ -81,19 +81,19 @@ function findHelper(keys, findFns = {}) { } function matchDirectory(ref, data, mode) { - return data.find(({ directory }) => directory === ref); + return data.find(({directory}) => directory === ref); } function matchName(ref, data, mode) { const matches = data.filter( - ({ name }) => name.toLowerCase() === ref.toLowerCase() + ({name}) => name.toLowerCase() === ref.toLowerCase() ); if (matches.length > 1) { return warnOrThrow( mode, `Multiple matches for reference "${ref}". Please resolve:\n` + - matches.map((match) => `- ${inspect(match)}\n`).join("") + + matches.map((match) => `- ${inspect(match)}\n`).join('') + `Returning null for this reference.` ); } @@ -115,19 +115,19 @@ function matchName(ref, data, mode) { } function matchTagName(ref, data, quiet) { - return matchName(ref.startsWith("cw: ") ? ref.slice(4) : ref, data, quiet); + return matchName(ref.startsWith('cw: ') ? ref.slice(4) : ref, data, quiet); } const find = { - album: findHelper(["album", "album-commentary"]), - artist: findHelper(["artist", "artist-gallery"]), - artTag: findHelper(["tag"], { byName: matchTagName }), - flash: findHelper(["flash"]), - group: findHelper(["group", "group-gallery"]), - listing: findHelper(["listing"]), - newsEntry: findHelper(["news-entry"]), - staticPage: findHelper(["static"]), - track: findHelper(["track"]), + album: findHelper(['album', 'album-commentary']), + artist: findHelper(['artist', 'artist-gallery']), + artTag: findHelper(['tag'], {byName: matchTagName}), + flash: findHelper(['flash']), + group: findHelper(['group', 'group-gallery']), + listing: findHelper(['listing']), + newsEntry: findHelper(['news-entry']), + staticPage: findHelper(['static']), + track: findHelper(['track']), }; export default find; @@ -140,15 +140,15 @@ export default find; export function bindFind(wikiData, opts1) { return Object.fromEntries( Object.entries({ - album: "albumData", - artist: "artistData", - artTag: "artTagData", - flash: "flashData", - group: "groupData", - listing: "listingSpec", - newsEntry: "newsData", - staticPage: "staticPageData", - track: "trackData", + album: 'albumData', + artist: 'artistData', + artTag: 'artTagData', + flash: 'flashData', + group: 'groupData', + listing: 'listingSpec', + newsEntry: 'newsData', + staticPage: 'staticPageData', + track: 'trackData', }).map(([key, value]) => { const findFn = find[key]; const thingData = wikiData[value]; @@ -157,7 +157,7 @@ export function bindFind(wikiData, opts1) { opts1 ? (ref, opts2) => opts2 - ? findFn(ref, thingData, { ...opts1, ...opts2 }) + ? findFn(ref, thingData, {...opts1, ...opts2}) : findFn(ref, thingData, opts1) : (ref, opts2) => opts2 ? findFn(ref, thingData, opts2) : findFn(ref, thingData), diff --git a/src/util/html.js b/src/util/html.js index 913dc7b2..f5b7bdcc 100644 --- a/src/util/html.js +++ b/src/util/html.js @@ -1,23 +1,23 @@ -// @format -// +/** @format */ + // Some really simple functions for formatting HTML content. // COMPREHENSIVE! // https://html.spec.whatwg.org/multipage/syntax.html#void-elements export const selfClosingTags = [ - "area", - "base", - "br", - "col", - "embed", - "hr", - "img", - "input", - "link", - "meta", - "source", - "track", - "wbr", + 'area', + 'base', + 'br', + 'col', + 'embed', + 'hr', + 'img', + 'input', + 'link', + 'meta', + 'source', + 'track', + 'wbr', ]; // Pass to tag() as an attri8utes key to make tag() return a 8lank string @@ -32,7 +32,7 @@ export function tag(tagName, ...args) { let content; let attrs; - if (typeof args[0] === "object" && !Array.isArray(args[0])) { + if (typeof args[0] === 'object' && !Array.isArray(args[0])) { attrs = args[0]; content = args[1]; } else { @@ -44,7 +44,7 @@ export function tag(tagName, ...args) { } if (attrs?.[onlyIfContent] && !content) { - return ""; + return ''; } if (attrs) { @@ -59,17 +59,17 @@ export function tag(tagName, ...args) { } if (Array.isArray(content)) { - content = content.filter(Boolean).join("\n"); + content = content.filter(Boolean).join('\n'); } if (content) { - if (content.includes("\n")) { + if (content.includes('\n')) { return ( `<${openTag}>\n` + content - .split("\n") - .map((line) => " " + line + "\n") - .join("") + + .split('\n') + .map((line) => ' ' + line + '\n') + .join('') + `` ); } else { @@ -85,18 +85,18 @@ export function tag(tagName, ...args) { } export function escapeAttributeValue(value) { - return value.replaceAll('"', """).replaceAll("'", "'"); + return value.replaceAll('"', '"').replaceAll("'", '''); } export function attributes(attribs) { return Object.entries(attribs) .map(([key, val]) => { - if (typeof val === "undefined" || val === null) return [key, val, false]; - else if (typeof val === "string") return [key, val, true]; - else if (typeof val === "boolean") return [key, val, val]; - else if (typeof val === "number") return [key, val.toString(), true]; + if (typeof val === 'undefined' || val === null) return [key, val, false]; + else if (typeof val === 'string') return [key, val, true]; + else if (typeof val === 'boolean') return [key, val, val]; + else if (typeof val === 'number') return [key, val.toString(), true]; else if (Array.isArray(val)) - return [key, val.filter(Boolean).join(" "), val.length > 0]; + return [key, val.filter(Boolean).join(' '), val.length > 0]; else throw new Error( `Attribute value for ${key} should be primitive or array, got ${typeof val}` @@ -104,9 +104,9 @@ export function attributes(attribs) { }) .filter(([key, val, keep]) => keep) .map(([key, val]) => - typeof val === "boolean" + typeof val === 'boolean' ? `${key}` : `${key}="${escapeAttributeValue(val)}"` ) - .join(" "); + .join(' '); } diff --git a/src/util/io.js b/src/util/io.js index 6ea1e221..5c1ab240 100644 --- a/src/util/io.js +++ b/src/util/io.js @@ -1,14 +1,14 @@ -// @format -// +/** @format */ + // Utility functions for interacting with files and other external data // interfacey constructs. -import { readdir } from "fs/promises"; -import * as path from "path"; +import {readdir} from 'fs/promises'; +import * as path from 'path'; export async function findFiles( dataPath, - { filter = (f) => true, joinParentDirectory = true } = {} + {filter = (f) => true, joinParentDirectory = true} = {} ) { return (await readdir(dataPath)) .filter((file) => filter(file)) diff --git a/src/util/link.js b/src/util/link.js index 4095b17d..ee3579d5 100644 --- a/src/util/link.js +++ b/src/util/link.js @@ -1,5 +1,5 @@ -// @format -// +/** @format */ + // This file is essentially one level of a8straction a8ove urls.js (and the // urlSpec it gets its paths from). It's a 8unch of utility functions which // take certain types of wiki data o8jects (colloquially known as "things") @@ -11,74 +11,74 @@ // options availa8le in all the functions, making a common interface for // gener8ting just a8out any link on the site. -import * as html from "./html.js"; -import { getColors } from "./colors.js"; +import * as html from './html.js'; +import {getColors} from './colors.js'; export function getLinkThemeString(color) { - if (!color) return ""; + if (!color) return ''; - const { primary, dim } = getColors(color); + const {primary, dim} = getColors(color); return `--primary-color: ${primary}; --dim-color: ${dim}`; } const appendIndexHTMLRegex = /^(?!https?:\/\/).+\/$/; const linkHelper = - (hrefFn, { color = true, attr = null } = {}) => + (hrefFn, {color = true, attr = null} = {}) => ( thing, { to, - text = "", + text = '', attributes = null, - class: className = "", + class: className = '', color: color2 = true, - hash = "", + hash = '', } ) => { - let href = hrefFn(thing, { to }); + let href = hrefFn(thing, {to}); if (link.globalOptions.appendIndexHTML) { if (appendIndexHTMLRegex.test(href)) { - href += "index.html"; + href += 'index.html'; } } if (hash) { - href += (hash.startsWith("#") ? "" : "#") + hash; + href += (hash.startsWith('#') ? '' : '#') + hash; } return html.tag( - "a", + 'a', { ...(attr ? attr(thing) : {}), ...(attributes ? attributes : {}), href, style: - typeof color2 === "string" + typeof color2 === 'string' ? getLinkThemeString(color2) : color2 && color ? getLinkThemeString(thing.color) - : "", + : '', class: className, }, text || thing.name ); }; -const linkDirectory = (key, { expose = null, attr = null, ...conf } = {}) => - linkHelper((thing, { to }) => to("localized." + key, thing.directory), { +const linkDirectory = (key, {expose = null, attr = null, ...conf} = {}) => + linkHelper((thing, {to}) => to('localized.' + key, thing.directory), { attr: (thing) => ({ ...(attr ? attr(thing) : {}), - ...(expose ? { [expose]: thing.directory } : {}), + ...(expose ? {[expose]: thing.directory} : {}), }), ...conf, }); const linkPathname = (key, conf) => - linkHelper(({ directory: pathname }, { to }) => to(key, pathname), conf); + linkHelper(({directory: pathname}, {to}) => to(key, pathname), conf); const linkIndex = (key, conf) => - linkHelper((_, { to }) => to("localized." + key), conf); + linkHelper((_, {to}) => to('localized.' + key), conf); const link = { globalOptions: { @@ -90,50 +90,50 @@ const link = { appendIndexHTML: false, }, - album: linkDirectory("album"), - albumCommentary: linkDirectory("albumCommentary"), - artist: linkDirectory("artist", { color: false }), - artistGallery: linkDirectory("artistGallery", { color: false }), - commentaryIndex: linkIndex("commentaryIndex", { color: false }), - flashIndex: linkIndex("flashIndex", { color: false }), - flash: linkDirectory("flash"), - groupInfo: linkDirectory("groupInfo"), - groupGallery: linkDirectory("groupGallery"), - home: linkIndex("home", { color: false }), - listingIndex: linkIndex("listingIndex"), - listing: linkDirectory("listing"), - newsIndex: linkIndex("newsIndex", { color: false }), - newsEntry: linkDirectory("newsEntry", { color: false }), - staticPage: linkDirectory("staticPage", { color: false }), - tag: linkDirectory("tag"), - track: linkDirectory("track", { expose: "data-track" }), + album: linkDirectory('album'), + albumCommentary: linkDirectory('albumCommentary'), + artist: linkDirectory('artist', {color: false}), + artistGallery: linkDirectory('artistGallery', {color: false}), + commentaryIndex: linkIndex('commentaryIndex', {color: false}), + flashIndex: linkIndex('flashIndex', {color: false}), + flash: linkDirectory('flash'), + groupInfo: linkDirectory('groupInfo'), + groupGallery: linkDirectory('groupGallery'), + home: linkIndex('home', {color: false}), + listingIndex: linkIndex('listingIndex'), + listing: linkDirectory('listing'), + newsIndex: linkIndex('newsIndex', {color: false}), + newsEntry: linkDirectory('newsEntry', {color: false}), + staticPage: linkDirectory('staticPage', {color: false}), + tag: linkDirectory('tag'), + track: linkDirectory('track', {expose: 'data-track'}), // TODO: This is a bit hacky. Files are just strings (not objects), so we // have to manually provide the album alongside the file. They also don't // follow the usual {name: whatever} type shape, so we have to provide that // ourselves. _albumAdditionalFileHelper: linkHelper( - (fakeFileObject, { to }) => + (fakeFileObject, {to}) => to( - "media.albumAdditionalFile", + 'media.albumAdditionalFile', fakeFileObject.album.directory, fakeFileObject.name ), - { color: false } + {color: false} ), - albumAdditionalFile: ({ file, album }, { to }) => + albumAdditionalFile: ({file, album}, {to}) => link._albumAdditionalFileHelper( { name: file, album, }, - { to } + {to} ), - media: linkPathname("media.path", { color: false }), - root: linkPathname("shared.path", { color: false }), - data: linkPathname("data.path", { color: false }), - site: linkPathname("localized.path", { color: false }), + media: linkPathname('media.path', {color: false}), + root: linkPathname('shared.path', {color: false}), + data: linkPathname('data.path', {color: false}), + site: linkPathname('localized.path', {color: false}), }; export default link; diff --git a/src/util/magic-constants.js b/src/util/magic-constants.js index a7b29332..dbdbcfda 100644 --- a/src/util/magic-constants.js +++ b/src/util/magic-constants.js @@ -1,5 +1,5 @@ -// @format -// +/** @format */ + // Magic constants only! These are hard-coded, and any use of them should be // considered a flaw in the codebase - areas where we use hard-coded behavior // to support one use of the wiki software (i.e. HSMusic, usually), rather than @@ -8,5 +8,5 @@ // All such uses should eventually be replaced with better code in due time // (TM). -export const OFFICIAL_GROUP_DIRECTORY = "official"; -export const FANDOM_GROUP_DIRECTORY = "fandom"; +export const OFFICIAL_GROUP_DIRECTORY = 'official'; +export const FANDOM_GROUP_DIRECTORY = 'fandom'; diff --git a/src/util/node-utils.js b/src/util/node-utils.js index f638e4ad..df446654 100644 --- a/src/util/node-utils.js +++ b/src/util/node-utils.js @@ -1,10 +1,10 @@ -// @format -// +/** @format */ + // Utility functions which are only relevant to particular Node.js constructs. -import { fileURLToPath } from "url"; +import {fileURLToPath} from 'url'; -import _commandExists from "command-exists"; +import _commandExists from 'command-exists'; // This package throws an error instead of returning false when the command // doesn't exist, for some reason. Yay for making logic more difficult! @@ -32,7 +32,7 @@ export function promisifyProcess(proc, showLogging = true) { proc.stderr.pipe(process.stderr); } - proc.on("exit", (code) => { + proc.on('exit', (code) => { if (code === 0) { resolve(); } else { diff --git a/src/util/replacer.js b/src/util/replacer.js index 10603b6c..6f4d0e9b 100644 --- a/src/util/replacer.js +++ b/src/util/replacer.js @@ -1,14 +1,14 @@ -// @format +/** @format */ -import { logError, logWarn } from "./cli.js"; -import { escapeRegex } from "./sugar.js"; +import {logError, logWarn} from './cli.js'; +import {escapeRegex} from './sugar.js'; -export function validateReplacerSpec(replacerSpec, { find, link }) { +export function validateReplacerSpec(replacerSpec, {find, link}) { let success = true; for (const [ key, - { link: linkKey, find: findKey, value, html }, + {link: linkKey, find: findKey, value, html}, ] of Object.entries(replacerSpec)) { if (!html && !link[linkKey]) { logError`The replacer spec ${key} has invalid link key ${linkKey}! Specify it in link specs or fix typo.`; @@ -24,15 +24,15 @@ export function validateReplacerSpec(replacerSpec, { find, link }) { } // Syntax literals. -const tagBeginning = "[["; -const tagEnding = "]]"; -const tagReplacerValue = ":"; -const tagHash = "#"; -const tagArgument = "*"; -const tagArgumentValue = "="; -const tagLabel = "|"; +const tagBeginning = '[['; +const tagEnding = ']]'; +const tagReplacerValue = ':'; +const tagHash = '#'; +const tagArgument = '*'; +const tagArgumentValue = '='; +const tagLabel = '|'; -const noPrecedingWhitespace = "(? ({ i, type: "error", data: { message } }); +const makeError = (i, message) => ({i, type: 'error', data: {message}}); const endOfInput = (i, comment) => makeError(i, `Unexpected end of input (${comment}).`); @@ -67,7 +67,7 @@ function parseOneTextNode(input, i, stopAt) { function parseNodes(input, i, stopAt, textOnly) { let nodes = []; let escapeNext = false; - let string = ""; + let string = ''; let iString = 0; stopped = false; @@ -82,8 +82,8 @@ function parseNodes(input, i, stopAt, textOnly) { } if (string.length) { - nodes.push({ i: iString, iEnd: i, type: "text", data: string }); - string = ""; + nodes.push({i: iString, iEnd: i, type: 'text', data: string}); + string = ''; } }; @@ -97,7 +97,7 @@ function parseNodes(input, i, stopAt, textOnly) { // should 8e counted only as part of the current string/text. // // Inspired 8y this: https://stackoverflow.com/a/41470813 - const regexpSource = `(?= 0) { lineStart += 1; } else { lineStart = 0; } - let lineEnd = input.slice(i).indexOf("\n"); + let lineEnd = input.slice(i).indexOf('\n'); if (lineEnd >= 0) { lineEnd += i; } else { @@ -334,18 +334,18 @@ export function parseInput(input) { throw new SyntaxError(fixWS` Parse error (at pos ${i}): ${message} ${line} - ${"-".repeat(cursor) + "^"} + ${'-'.repeat(cursor) + '^'} `); } } function evaluateTag(node, opts) { - const { find, input, language, link, replacerSpec, to, wikiData } = opts; + const {find, input, language, link, replacerSpec, to, wikiData} = opts; const source = input.slice(node.i, node.iEnd); const replacerKeyImplied = !node.data.replacerKey; - const replacerKey = replacerKeyImplied ? "track" : node.data.replacerKey.data; + const replacerKey = replacerKeyImplied ? 'track' : node.data.replacerKey.data; if (!replacerSpec[replacerKey]) { logWarn`The link ${source} has an invalid replacer key!`; @@ -395,7 +395,7 @@ function evaluateTag(node, opts) { const args = node.data.args && Object.fromEntries( - node.data.args.map(({ key, value }) => [ + node.data.args.map(({key, value}) => [ transformNode(key, opts), transformNodes(value, opts), ]) @@ -404,7 +404,7 @@ function evaluateTag(node, opts) { const fn = htmlFn ? htmlFn : link[linkKey]; try { - return fn(value, { text: label, hash, args, language, to }); + return fn(value, {text: label, hash, args, language, to}); } catch (error) { logError`The link ${source} failed to be processed: ${error}`; return source; @@ -413,17 +413,17 @@ function evaluateTag(node, opts) { function transformNode(node, opts) { if (!node) { - throw new Error("Expected a node!"); + throw new Error('Expected a node!'); } if (Array.isArray(node)) { - throw new Error("Got an array - use transformNodes here!"); + throw new Error('Got an array - use transformNodes here!'); } switch (node.type) { - case "text": + case 'text': return node.data; - case "tag": + case 'tag': return evaluateTag(node, opts); default: throw new Error(`Unknown node type ${node.type}`); @@ -435,19 +435,19 @@ function transformNodes(nodes, opts) { throw new Error(`Expected an array of nodes! Got: ${nodes}`); } - return nodes.map((node) => transformNode(node, opts)).join(""); + return nodes.map((node) => transformNode(node, opts)).join(''); } export function transformInline( input, - { replacerSpec, find, link, language, to, wikiData } + {replacerSpec, find, link, language, to, wikiData} ) { - if (!replacerSpec) throw new Error("Expected replacerSpec"); - if (!find) throw new Error("Expected find"); - if (!link) throw new Error("Expected link"); - if (!language) throw new Error("Expected language"); - if (!to) throw new Error("Expected to"); - if (!wikiData) throw new Error("Expected wikiData"); + if (!replacerSpec) throw new Error('Expected replacerSpec'); + if (!find) throw new Error('Expected find'); + if (!link) throw new Error('Expected link'); + if (!language) throw new Error('Expected language'); + if (!to) throw new Error('Expected to'); + if (!wikiData) throw new Error('Expected wikiData'); const nodes = parseInput(input); return transformNodes(nodes, { diff --git a/src/util/serialize.js b/src/util/serialize.js index ab864836..9aa8b0c5 100644 --- a/src/util/serialize.js +++ b/src/util/serialize.js @@ -1,4 +1,4 @@ -// @format +/** @format */ export function serializeLink(thing) { const ret = {}; @@ -9,7 +9,7 @@ export function serializeLink(thing) { } export function serializeContribs(contribs) { - return contribs.map(({ who, what }) => { + return contribs.map(({who, what}) => { const ret = {}; ret.artist = serializeLink(who); if (what) ret.contribution = what; @@ -17,7 +17,7 @@ export function serializeContribs(contribs) { }); } -export function serializeImagePaths(original, { thumb }) { +export function serializeImagePaths(original, {thumb}) { return { original, medium: thumb.medium(original), @@ -28,13 +28,13 @@ export function serializeImagePaths(original, { thumb }) { export function serializeCover( thing, pathFunction, - { serializeImagePaths, urls } + {serializeImagePaths, urls} ) { const coverPath = pathFunction(thing, { - to: urls.from("media.root").to, + to: urls.from('media.root').to, }); - const { artTags } = thing; + const {artTags} = thing; const cwTags = artTags.filter((tag) => tag.isContentWarning); const linkTags = artTags.filter((tag) => !tag.isContentWarning); @@ -46,15 +46,15 @@ export function serializeCover( }; } -export function serializeGroupsForAlbum(album, { serializeLink }) { +export function serializeGroupsForAlbum(album, {serializeLink}) { return album.groups .map((group) => { const index = group.albums.indexOf(album); const next = group.albums[index + 1] || null; const previous = group.albums[index - 1] || null; - return { group, index, next, previous }; + return {group, index, next, previous}; }) - .map(({ group, index, next, previous }) => ({ + .map(({group, index, next, previous}) => ({ link: serializeLink(group), descriptionShort: group.descriptionShort, albumIndex: index, @@ -64,7 +64,7 @@ export function serializeGroupsForAlbum(album, { serializeLink }) { })); } -export function serializeGroupsForTrack(track, { serializeLink }) { +export function serializeGroupsForTrack(track, {serializeLink}) { return track.album.groups.map((group) => ({ link: serializeLink(group), urls: group.urls, diff --git a/src/util/sugar.js b/src/util/sugar.js index a4504daa..0a5de482 100644 --- a/src/util/sugar.js +++ b/src/util/sugar.js @@ -1,5 +1,5 @@ -// @format -// +/** @format */ + // Syntactic sugar! (Mostly.) // Generic functions - these are useful just a8out everywhere. // @@ -8,7 +8,7 @@ // It will likely only do exactly what I want it to, and only in the cases I // decided were relevant enough to 8other handling. -import { color } from "./cli.js"; +import {color} from './cli.js'; // Apparently JavaScript doesn't come with a function to split an array into // chunks! Weird. Anyway, this is an awesome place to use a generator, even @@ -35,13 +35,13 @@ export const mapInPlace = (array, fn) => export const filterEmptyLines = (string) => string - .split("\n") + .split('\n') .filter((line) => line.trim()) - .join("\n"); + .join('\n'); export const unique = (arr) => Array.from(new Set(arr)); -export const compareArrays = (arr1, arr2, { checkOrder = true } = {}) => +export const compareArrays = (arr1, arr2, {checkOrder = true} = {}) => arr1.length === arr2.length && (checkOrder ? arr1.every((x, i) => arr2[i] === x) @@ -90,7 +90,7 @@ export function delay(ms) { // There's a proposal for a native JS function like this, 8ut it's not even // past stage 1 yet: https://github.com/tc39/proposal-regex-escaping export function escapeRegex(string) { - return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } export function bindOpts(fn, bind) { @@ -98,10 +98,10 @@ export function bindOpts(fn, bind) { const bound = function (...args) { const opts = args[bindIndex] ?? {}; - return fn(...args.slice(0, bindIndex), { ...bind, ...opts }); + return fn(...args.slice(0, bindIndex), {...bind, ...opts}); }; - Object.defineProperty(bound, "name", { + Object.defineProperty(bound, 'name', { value: fn.name ? `(options-bound) ${fn.name}` : `(options-bound)`, }); @@ -132,7 +132,7 @@ export function openAggregate({ // Optional human-readable message to describe the aggregate error, if // constructed. - message = "", + message = '', // Value to return when a provided function throws an error. If this is a // function, it will be called with the arguments given to the function. @@ -151,7 +151,7 @@ export function openAggregate({ return fn(...args); } catch (error) { errors.push(error); - return typeof returnOnFail === "function" + return typeof returnOnFail === 'function' ? returnOnFail(...args) : returnOnFail; } @@ -164,7 +164,7 @@ export function openAggregate({ (value) => value, (error) => { errors.push(error); - return typeof returnOnFail === "function" + return typeof returnOnFail === 'function' ? returnOnFail(...args) : returnOnFail; } @@ -189,21 +189,21 @@ export function openAggregate({ aggregate.map = (...args) => { const parent = aggregate; - const { result, aggregate: child } = mapAggregate(...args); + const {result, aggregate: child} = mapAggregate(...args); parent.call(child.close); return result; }; aggregate.mapAsync = async (...args) => { const parent = aggregate; - const { result, aggregate: child } = await mapAggregateAsync(...args); + const {result, aggregate: child} = await mapAggregateAsync(...args); parent.call(child.close); return result; }; aggregate.filter = (...args) => { const parent = aggregate; - const { result, aggregate: child } = filterAggregate(...args); + const {result, aggregate: child} = filterAggregate(...args); parent.call(child.close); return result; }; @@ -219,11 +219,11 @@ export function openAggregate({ return aggregate; } -openAggregate.errorClassSymbol = Symbol("error class"); +openAggregate.errorClassSymbol = Symbol('error class'); // Utility function for providing {errorClass} parameter to aggregate functions. export function aggregateThrows(errorClass) { - return { [openAggregate.errorClassSymbol]: errorClass }; + return {[openAggregate.errorClassSymbol]: errorClass}; } // Performs an ordinary array map with the given function, collating into a @@ -236,15 +236,15 @@ export function aggregateThrows(errorClass) { // use aggregate.close() to throw the error. (This aggregate may be passed to a // parent aggregate: `parent.call(aggregate.close)`!) export function mapAggregate(array, fn, aggregateOpts) { - return _mapAggregate("sync", null, array, fn, aggregateOpts); + return _mapAggregate('sync', null, array, fn, aggregateOpts); } export function mapAggregateAsync( array, fn, - { promiseAll = Promise.all.bind(Promise), ...aggregateOpts } = {} + {promiseAll = Promise.all.bind(Promise), ...aggregateOpts} = {} ) { - return _mapAggregate("async", promiseAll, array, fn, aggregateOpts); + return _mapAggregate('async', promiseAll, array, fn, aggregateOpts); } // Helper function for mapAggregate which holds code common between sync and @@ -257,15 +257,15 @@ export function _mapAggregate(mode, promiseAll, array, fn, aggregateOpts) { ...aggregateOpts, }); - if (mode === "sync") { + if (mode === 'sync') { const result = array .map(aggregate.wrap(fn)) .filter((value) => value !== failureSymbol); - return { result, aggregate }; + return {result, aggregate}; } else { return promiseAll(array.map(aggregate.wrapAsync(fn))).then((values) => { const result = values.filter((value) => value !== failureSymbol); - return { result, aggregate }; + return {result, aggregate}; }); } } @@ -278,15 +278,15 @@ export function _mapAggregate(mode, promiseAll, array, fn, aggregateOpts) { // // As with mapAggregate, the returned aggregate property is not yet closed. export function filterAggregate(array, fn, aggregateOpts) { - return _filterAggregate("sync", null, array, fn, aggregateOpts); + return _filterAggregate('sync', null, array, fn, aggregateOpts); } export async function filterAggregateAsync( array, fn, - { promiseAll = Promise.all.bind(Promise), ...aggregateOpts } = {} + {promiseAll = Promise.all.bind(Promise), ...aggregateOpts} = {} ) { - return _filterAggregate("async", promiseAll, array, fn, aggregateOpts); + return _filterAggregate('async', promiseAll, array, fn, aggregateOpts); } // Helper function for filterAggregate which holds code common between sync and @@ -326,30 +326,30 @@ function _filterAggregate(mode, promiseAll, array, fn, aggregateOpts) { }; } - if (mode === "sync") { + if (mode === 'sync') { const result = array .map( aggregate.wrap((input, index, array) => { const output = fn(input, index, array); - return { input, output }; + return {input, output}; }) ) .filter(filterFunction) .map(mapFunction); - return { result, aggregate }; + return {result, aggregate}; } else { return promiseAll( array.map( aggregate.wrapAsync(async (input, index, array) => { const output = await fn(input, index, array); - return { input, output }; + return {input, output}; }) ) ).then((values) => { const result = values.filter(filterFunction).map(mapFunction); - return { result, aggregate }; + return {result, aggregate}; }); } } @@ -358,22 +358,22 @@ function _filterAggregate(mode, promiseAll, array, fn, aggregateOpts) { // function with it, then closing the function and returning the result (if // there's no throw). export function withAggregate(aggregateOpts, fn) { - return _withAggregate("sync", aggregateOpts, fn); + return _withAggregate('sync', aggregateOpts, fn); } export function withAggregateAsync(aggregateOpts, fn) { - return _withAggregate("async", aggregateOpts, fn); + return _withAggregate('async', aggregateOpts, fn); } export function _withAggregate(mode, aggregateOpts, fn) { - if (typeof aggregateOpts === "function") { + if (typeof aggregateOpts === 'function') { fn = aggregateOpts; aggregateOpts = {}; } const aggregate = openAggregate(aggregateOpts); - if (mode === "sync") { + if (mode === 'sync') { const result = fn(aggregate); aggregate.close(); return result; @@ -387,56 +387,56 @@ export function _withAggregate(mode, aggregateOpts, fn) { export function showAggregate( topError, - { pathToFile = (p) => p, showTraces = true } = {} + {pathToFile = (p) => p, showTraces = true} = {} ) { - const recursive = (error, { level }) => { + const recursive = (error, {level}) => { let header = showTraces - ? `[${error.constructor.name || "unnamed"}] ${ - error.message || "(no message)" + ? `[${error.constructor.name || 'unnamed'}] ${ + error.message || '(no message)' }` : error instanceof AggregateError - ? `[${error.message || "(no message)"}]` - : error.message || "(no message)"; + ? `[${error.message || '(no message)'}]` + : error.message || '(no message)'; if (showTraces) { - const stackLines = error.stack?.split("\n"); + const stackLines = error.stack?.split('\n'); const stackLine = stackLines?.find( (line) => - line.trim().startsWith("at") && - !line.includes("sugar") && - !line.includes("node:") && - !line.includes("") + line.trim().startsWith('at') && + !line.includes('sugar') && + !line.includes('node:') && + !line.includes('') ); const tracePart = stackLine - ? "- " + + ? '- ' + stackLine .trim() .replace(/file:\/\/(.*\.js)/, (match, pathname) => pathToFile(pathname) ) - : "(no stack trace)"; + : '(no stack trace)'; header += ` ${color.dim(tracePart)}`; } - const bar = level % 2 === 0 ? "\u2502" : color.dim("\u254e"); - const head = level % 2 === 0 ? "\u257f" : color.dim("\u257f"); + const bar = level % 2 === 0 ? '\u2502' : color.dim('\u254e'); + const head = level % 2 === 0 ? '\u257f' : color.dim('\u257f'); if (error instanceof AggregateError) { return ( header + - "\n" + + '\n' + error.errors - .map((error) => recursive(error, { level: level + 1 })) - .flatMap((str) => str.split("\n")) + .map((error) => recursive(error, {level: level + 1})) + .flatMap((str) => str.split('\n')) .map((line, i, lines) => i === 0 ? ` ${head} ${line}` : ` ${bar} ${line}` ) - .join("\n") + .join('\n') ); } else { return header; } }; - console.error(recursive(topError, { level: 0 })); + console.error(recursive(topError, {level: 0})); } export function decorateErrorWithIndex(fn) { diff --git a/src/util/urls.js b/src/util/urls.js index 4e398082..ce747df2 100644 --- a/src/util/urls.js +++ b/src/util/urls.js @@ -1,5 +1,5 @@ -// @format -// +/** @format */ + // Code that deals with URLs (really the pathnames that get referenced all // throughout the gener8ted HTML). Most nota8ly here is generateURLs, which // is in charge of pre-gener8ting a complete network of template strings @@ -10,12 +10,12 @@ // actual path strings. More a8stract operations using wiki data o8jects is // the domain of link.js. -import * as path from "path"; -import { withEntries } from "./sugar.js"; +import * as path from 'path'; +import {withEntries} from './sugar.js'; export function generateURLs(urlSpec) { const getValueForFullKey = (obj, fullKey, prop = null) => { - const [groupKey, subKey] = fullKey.split("."); + const [groupKey, subKey] = fullKey.split('.'); if (!groupKey || !subKey) { throw new Error(`Expected group key and subkey (got ${fullKey})`); } @@ -41,27 +41,27 @@ export function generateURLs(urlSpec) { // This should be called on values which are going to be passed to // path.relative, because relative will resolve a leading slash as the root // directory of the working device, which we aren't looking for here. - const trimLeadingSlash = (P) => (P.startsWith("/") ? P.slice(1) : P); + const trimLeadingSlash = (P) => (P.startsWith('/') ? P.slice(1) : P); const generateTo = (fromPath, fromGroup) => { const A = trimLeadingSlash(fromPath); - const rebasePrefix = "../".repeat( - (fromGroup.prefix || "").split("/").filter(Boolean).length + const rebasePrefix = '../'.repeat( + (fromGroup.prefix || '').split('/').filter(Boolean).length ); const pathHelper = (toPath, toGroup) => { let B = trimLeadingSlash(toPath); let argIndex = 0; - B = B.replaceAll("<>", () => `<${argIndex++}>`); + B = B.replaceAll('<>', () => `<${argIndex++}>`); if (toGroup.prefix !== fromGroup.prefix) { // TODO: Handle differing domains in prefixes. - B = rebasePrefix + (toGroup.prefix || "") + B; + B = rebasePrefix + (toGroup.prefix || '') + B; } - const suffix = toPath.endsWith("/") ? "/" : ""; + const suffix = toPath.endsWith('/') ? '/' : ''; return { posix: path.posix.relative(A, B) + suffix, @@ -86,7 +86,7 @@ export function generateURLs(urlSpec) { (delimiterMode) => (key, ...args) => { const { - value: { [delimiterMode]: template }, + value: {[delimiterMode]: template}, } = getValueForFullKey(relative, key); let missing = 0; @@ -110,8 +110,8 @@ export function generateURLs(urlSpec) { }; return { - to: toHelper("posix"), - toDevice: toHelper("device"), + to: toHelper('posix'), + toDevice: toHelper('device'), }; }; @@ -127,16 +127,16 @@ export function generateURLs(urlSpec) { const from = (key) => getValueForFullKey(map, key).value; - return { from, map }; + return {from, map}; }; return generateFrom(); } const thumbnailHelper = (name) => (file) => - file.replace(/\.(jpg|png)$/, name + ".jpg"); + file.replace(/\.(jpg|png)$/, name + '.jpg'); export const thumb = { - medium: thumbnailHelper(".medium"), - small: thumbnailHelper(".small"), + medium: thumbnailHelper('.medium'), + small: thumbnailHelper('.small'), }; diff --git a/src/util/wiki-data.js b/src/util/wiki-data.js index 7e16580d..65eb7d7c 100644 --- a/src/util/wiki-data.js +++ b/src/util/wiki-data.js @@ -1,17 +1,17 @@ -// @format -// +/** @format */ + // Utility functions for interacting with wiki data. // Generic value operations export function getKebabCase(name) { return name - .split(" ") - .join("-") - .replace(/&/g, "and") - .replace(/[^a-zA-Z0-9\-]/g, "") - .replace(/-{2,}/g, "-") - .replace(/^-+|-+$/g, "") + .split(' ') + .join('-') + .replace(/&/g, 'and') + .replace(/[^a-zA-Z0-9\-]/g, '') + .replace(/-{2,}/g, '-') + .replace(/^-+|-+$/g, '') .toLowerCase(); } @@ -81,8 +81,8 @@ export function compareCaseLessSensitive(a, b) { const bl = b.toLowerCase(); return al === bl - ? a.localeCompare(b, undefined, { numeric: true }) - : al.localeCompare(bl, undefined, { numeric: true }); + ? a.localeCompare(b, undefined, {numeric: true}) + : al.localeCompare(bl, undefined, {numeric: true}); } // Subtract common prefixes and other characters which some people don't like @@ -92,22 +92,22 @@ export function normalizeName(s) { // Turn (some) ligatures into expanded variant for cleaner sorting, e.g. // "ff" into "ff", in decompose mode, so that "ü" is represented as two // bytes ("u" + \u0308 combining diaeresis). - s = s.normalize("NFKD"); + s = s.normalize('NFKD'); // Replace one or more whitespace of any kind in a row, as well as certain // punctuation, with a single typical space, then trim the ends. s = s .replace( /[\p{Separator}\p{Dash_Punctuation}\p{Connector_Punctuation}]+/gu, - " " + ' ' ) .trim(); // Discard anything that isn't a letter, number, or space. - s = s.replace(/[^\p{Letter}\p{Number} ]/gu, ""); + s = s.replace(/[^\p{Letter}\p{Number} ]/gu, ''); // Remove common English (only, for now) prefixes. - s = s.replace(/^(?:an?|the) /i, ""); + s = s.replace(/^(?:an?|the) /i, ''); return s; } @@ -142,7 +142,7 @@ export function normalizeName(s) { // except when album and track directories overlap with each other. export function sortByDirectory( data, - { getDirectory = (o) => o.directory } = {} + {getDirectory = (o) => o.directory} = {} ) { return data.sort((a, b) => { const ad = getDirectory(a); @@ -151,7 +151,7 @@ export function sortByDirectory( }); } -export function sortByName(data, { getName = (o) => o.name } = {}) { +export function sortByName(data, {getName = (o) => o.name} = {}) { return data.sort((a, b) => { const an = getName(a); const bn = getName(b); @@ -163,7 +163,7 @@ export function sortByName(data, { getName = (o) => o.name } = {}) { }); } -export function sortByDate(data, { getDate = (o) => o.date } = {}) { +export function sortByDate(data, {getDate = (o) => o.date} = {}) { return data.sort((a, b) => { const ad = getDate(a); const bd = getDate(b); @@ -254,9 +254,9 @@ export function sortByConditions(data, conditions) { // Expects thing properties: // * directory (or override getDirectory) // * name (or override getName) -export function sortAlphabetically(data, { getDirectory, getName } = {}) { - sortByDirectory(data, { getDirectory }); - sortByName(data, { getName }); +export function sortAlphabetically(data, {getDirectory, getName} = {}) { + sortByDirectory(data, {getDirectory}); + sortByName(data, {getName}); return data; } @@ -266,10 +266,10 @@ export function sortAlphabetically(data, { getDirectory, getName } = {}) { // * date (or override getDate) export function sortChronologically( data, - { getDirectory, getName, getDate } = {} + {getDirectory, getName, getDate} = {} ) { - sortAlphabetically(data, { getDirectory, getName }); - sortByDate(data, { getDate }); + sortAlphabetically(data, {getDirectory, getName}); + sortByDate(data, {getDate}); return data; } @@ -281,7 +281,7 @@ export function sortChronologically( // release date but can be overridden) above all else. // // This function also works for data lists which contain only tracks. -export function sortAlbumsTracksChronologically(data, { getDate } = {}) { +export function sortAlbumsTracksChronologically(data, {getDate} = {}) { // Sort albums before tracks... sortByConditions(data, [(t) => t.album === undefined]); @@ -297,7 +297,7 @@ export function sortAlbumsTracksChronologically(data, { getDate } = {}) { // released on the same date, they'll still be grouped together by album, // and tracks within an album will retain their relative positioning (i.e. // stay in the same order as part of the album's track listing). - sortByDate(data, { getDate }); + sortByDate(data, {getDate}); return data; } @@ -310,17 +310,17 @@ export function filterAlbumsByCommentary(albums) { ); } -export function getAlbumCover(album, { to }) { +export function getAlbumCover(album, {to}) { // Some albums don't have art! This function returns null in that case. if (album.hasCoverArt) { - return to("media.albumCover", album.directory, album.coverArtFileExtension); + return to('media.albumCover', album.directory, album.coverArtFileExtension); } else { return null; } } export function getAlbumListTag(album) { - return album.hasTrackNumbers ? "ol" : "ul"; + return album.hasTrackNumbers ? 'ol' : 'ul'; } // This gets all the track o8jects defined in every al8um, and sorts them 8y @@ -352,8 +352,8 @@ export function getArtistNumContributions(artist) { ); } -export function getFlashCover(flash, { to }) { - return to("media.flashArt", flash.directory, flash.coverArtFileExtension); +export function getFlashCover(flash, {to}) { + return to('media.flashArt', flash.directory, flash.coverArtFileExtension); } export function getFlashLink(flash) { @@ -364,16 +364,16 @@ export function getTotalDuration(tracks) { return tracks.reduce((duration, track) => duration + track.duration, 0); } -export function getTrackCover(track, { to }) { +export function getTrackCover(track, {to}) { // Some albums don't have any track art at all, and in those, every track // just inherits the album's own cover art. Note that since cover art isn't // guaranteed on albums either, it's possible that this function returns // null! if (!track.hasCoverArt) { - return getAlbumCover(track.album, { to }); + return getAlbumCover(track.album, {to}); } else { return to( - "media.trackCover", + 'media.trackCover', track.album.directory, track.directory, track.coverArtFileExtension @@ -381,14 +381,14 @@ export function getTrackCover(track, { to }) { } } -export function getArtistAvatar(artist, { to }) { - return to("media.artistAvatar", artist.directory, artist.avatarFileExtension); +export function getArtistAvatar(artist, {to}) { + return to('media.artistAvatar', artist.directory, artist.avatarFileExtension); } // Big-ass homepage row functions -export function getNewAdditions(numAlbums, { wikiData }) { - const { albumData } = wikiData; +export function getNewAdditions(numAlbums, {wikiData}) { + const {albumData} = wikiData; // Sort al8ums, in descending order of priority, 8y... // @@ -486,11 +486,11 @@ export function getNewAdditions(numAlbums, { wikiData }) { // Finally, do some quick mapping shenanigans to 8etter display the result // in a grid. (This should pro8a8ly 8e a separ8te, shared function, 8ut // whatevs.) - return albums.map((album) => ({ large: album.isMajorRelease, item: album })); + return albums.map((album) => ({large: album.isMajorRelease, item: album})); } -export function getNewReleases(numReleases, { wikiData }) { - const { albumData } = wikiData; +export function getNewReleases(numReleases, {wikiData}) { + const {albumData} = wikiData; const latestFirst = albumData .filter((album) => album.isListedOnHomepage) @@ -503,7 +503,7 @@ export function getNewReleases(numReleases, { wikiData }) { .slice(0, numReleases - majorReleases.length); return [ - ...majorReleases.map((album) => ({ large: true, item: album })), - ...otherReleases.map((album) => ({ large: false, item: album })), + ...majorReleases.map((album) => ({large: true, item: album})), + ...otherReleases.map((album) => ({large: false, item: album})), ]; } -- cgit 1.3.0-6-gf8a5