diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2022-11-26 23:44:08 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2022-11-26 23:44:08 -0400 |
commit | 003f594f6348b55109dd66416e75fcc2a88faade (patch) | |
tree | b4cb05ed4e145e604356786a1d98926040fe5ff0 /src | |
parent | 768927503b5948b846b9a6cddf4b788ca9792e8c (diff) |
finish up cosmetic style changes
Diffstat (limited to 'src')
39 files changed, 906 insertions, 1198 deletions
diff --git a/src/data/cacheable-object.js b/src/data/cacheable-object.js index 688d8a0f..04e029f0 100644 --- a/src/data/cacheable-object.js +++ b/src/data/cacheable-object.js @@ -1,7 +1,3 @@ -/** - * @format - */ - // Generally extendable class for caching properties and handling dependencies, // with a few key properties: // @@ -112,9 +108,7 @@ export default class CacheableObject { get: (obj, key) => { if (!Object.hasOwn(obj, key)) { if (key !== 'constructor') { - CacheableObject._invalidAccesses.add( - `(${obj.constructor.name}).${key}` - ); + CacheableObject._invalidAccesses.add(`(${obj.constructor.name}).${key}`); } } return obj[key]; @@ -124,9 +118,7 @@ export default class CacheableObject { } #initializeUpdatingPropertyValues() { - for (const [property, descriptor] of Object.entries( - this.constructor.propertyDescriptors - )) { + for (const [property, descriptor] of Object.entries(this.constructor.propertyDescriptors)) { const {flags, update} = descriptor; if (!flags.update) { @@ -143,14 +135,10 @@ export default class CacheableObject { #defineProperties() { if (!this.constructor.propertyDescriptors) { - throw new Error( - `Expected constructor ${this.constructor.name} to define propertyDescriptors` - ); + throw new Error(`Expected constructor ${this.constructor.name} to define propertyDescriptors`); } - for (const [property, descriptor] of Object.entries( - this.constructor.propertyDescriptors - )) { + for (const [property, descriptor] of Object.entries(this.constructor.propertyDescriptors)) { const {flags} = descriptor; const definition = { @@ -159,13 +147,11 @@ export default class CacheableObject { }; if (flags.update) { - definition.set = - this.#getUpdateObjectDefinitionSetterFunction(property); + definition.set = this.#getUpdateObjectDefinitionSetterFunction(property); } if (flags.expose) { - definition.get = - this.#getExposeObjectDefinitionGetterFunction(property); + definition.get = this.#getExposeObjectDefinitionGetterFunction(property); } Object.defineProperty(this, property, definition); @@ -198,9 +184,11 @@ export default class CacheableObject { throw new TypeError(`Validation failed for value ${newValue}`); } } catch (error) { - error.message = `Property ${color.green(property)} (${inspect( - this[property] - )} -> ${inspect(newValue)}): ${error.message}`; + error.message = [ + `Property ${color.green(property)}`, + `(${inspect(this[property])} -> ${inspect(newValue)}):`, + error.message + ].join(' '); throw error; } } @@ -215,8 +203,12 @@ export default class CacheableObject { } #invalidateCachesDependentUpon(property) { - for (const invalidate of this.#propertyUpdateCacheInvalidators[property] || - []) { + const invalidators = this.#propertyUpdateCacheInvalidators[property]; + if (!invalidators) { + return; + } + + for (const invalidate of invalidators) { invalidate(); } } @@ -236,9 +228,7 @@ export default class CacheableObject { } }; } else if (!flags.update && !compute) { - throw new Error( - `Exposed property ${property} does not update and is missing compute function` - ); + throw new Error(`Exposed property ${property} does not update and is missing compute function`); } else { return () => this.#propertyUpdateValues[property]; } @@ -253,30 +243,31 @@ export default class CacheableObject { if (flags.update && !transform) { return null; } else if (flags.update && compute) { - throw new Error( - `Updating property ${property} has compute function, should be formatted as transform` - ); + throw new Error(`Updating property ${property} has compute function, should be formatted as transform`); } else if (!flags.update && !compute) { - throw new Error( - `Exposed property ${property} does not update and is missing compute function` - ); + throw new Error(`Exposed property ${property} does not update and is missing compute function`); } - const dependencyKeys = expose.dependencies || []; - const dependencyGetters = dependencyKeys.map((key) => () => [ - key, - this.#propertyUpdateValues[key], - ]); - const getAllDependencies = () => - Object.fromEntries( - dependencyGetters - .map((f) => f()) - .concat([[this.constructor.instance, this]]) - ); + let getAllDependencies; + + const dependencyKeys = expose.dependencies; + if (dependencyKeys?.length > 0) { + const reflectionEntry = [this.constructor.instance, this]; + const dependencyGetters = dependencyKeys + .map(key => () => [key, this.#propertyUpdateValues[key]]); + + getAllDependencies = () => + Object.fromEntries(dependencyGetters + .map(f => f()) + .concat([reflectionEntry])); + } else { + const allDependencies = {[this.constructor.instance]: this}; + Object.freeze(allDependencies); + getAllDependencies = () => allDependencies; + } if (flags.update) { - return () => - transform(this.#propertyUpdateValues[property], getAllDependencies()); + return () => transform(this.#propertyUpdateValues[property], getAllDependencies()); } else { return () => compute(getAllDependencies()); } @@ -321,14 +312,14 @@ export default class CacheableObject { return; } - if (!obj.constructor.propertyDescriptors) { + const {propertyDescriptors} = obj.constructor; + + if (!propertyDescriptors) { console.warn('Missing property descriptors:', obj); return; } - for (const [property, descriptor] of Object.entries( - obj.constructor.propertyDescriptors - )) { + for (const [property, descriptor] of Object.entries(propertyDescriptors)) { const {flags} = descriptor; if (!flags.expose) { diff --git a/src/data/patches.js b/src/data/patches.js index dc757fa9..feeaf39b 100644 --- a/src/data/patches.js +++ b/src/data/patches.js @@ -1,5 +1,3 @@ -/** @format */ - // --> Patch export class Patch { @@ -137,6 +135,7 @@ export class PatchManager extends Patch { this.#externalInputPatch = new PatchManagerExternalInputPatch({ manager: this, }); + this.#externalOutputPatch = new PatchManagerExternalOutputPatch({ manager: this, }); @@ -184,9 +183,7 @@ export class PatchManager extends Patch { addManagedInput(patchWithInput, inputName, patchWithOutput, outputName) { if (patchWithInput.manager !== this || patchWithOutput.manager !== this) { - throw new Error( - `Input and output patches must belong to same manager (this)` - ); + throw new Error(`Input and output patches must belong to same manager (this)`); } const input = patchWithInput.inputs[inputName]; diff --git a/src/data/serialize.js b/src/data/serialize.js index a4206fd0..52aacb07 100644 --- a/src/data/serialize.js +++ b/src/data/serialize.js @@ -1,6 +1,4 @@ -/** @format */ - -// serialize-util.js: simple interface and utility functions for converting +// serialize.js: simple interface and utility functions for converting // Things into a directly serializeable format // Utility functions @@ -27,17 +25,14 @@ export const serializeDescriptors = Symbol(); export function serializeThing(thing) { const descriptors = thing.constructor[serializeDescriptors]; + if (!descriptors) { - throw new Error( - `Constructor ${thing.constructor.name} does not provide serialize descriptors` - ); + throw new Error(`Constructor ${thing.constructor.name} does not provide serialize descriptors`); } return Object.fromEntries( - Object.entries(descriptors).map(([property, transform]) => [ - property, - transform(thing[property]), - ]) + Object.entries(descriptors) + .map(([property, transform]) => [property, transform(thing[property])]) ); } diff --git a/src/data/things.js b/src/data/things.js index 4aa684d4..33880460 100644 --- a/src/data/things.js +++ b/src/data/things.js @@ -1,5 +1,3 @@ -/** @format */ - // things.js: class definitions for various object types used across the wiki, // most of which correspond to an output page, such as Track, Album, Artist @@ -236,9 +234,7 @@ Thing.common = { referenceList: (thingClass) => { const {[Thing.referenceType]: referenceType} = thingClass; if (!referenceType) { - throw new Error( - `The passed constructor ${thingClass.name} doesn't define Thing.referenceType!` - ); + throw new Error(`The passed constructor ${thingClass.name} doesn't define Thing.referenceType!`); } return { @@ -251,9 +247,7 @@ Thing.common = { singleReference: (thingClass) => { const {[Thing.referenceType]: referenceType} = thingClass; if (!referenceType) { - throw new Error( - `The passed constructor ${thingClass.name} doesn't define Thing.referenceType!` - ); + throw new Error(`The passed constructor ${thingClass.name} doesn't define Thing.referenceType!`); } return { @@ -441,15 +435,13 @@ Thing.common = { // constructor's [Thing.referenceType] as the prefix. This will throw an error // if the thing's directory isn't yet provided/computable. Thing.getReference = function (thing) { - if (!thing.constructor[Thing.referenceType]) - throw TypeError( - `Passed Thing is ${thing.constructor.name}, which provides no [Thing.referenceType]` - ); + if (!thing.constructor[Thing.referenceType]) { + throw TypeError(`Passed Thing is ${thing.constructor.name}, which provides no [Thing.referenceType]`); + } - if (!thing.directory) - throw TypeError( - `Passed ${thing.constructor.name} is missing its directory` - ); + if (!thing.directory) { + throw TypeError(`Passed ${thing.constructor.name} is missing its directory`); + } return `${thing.constructor[Thing.referenceType]}:${thing.directory}`; }; @@ -735,10 +727,11 @@ Track.propertyDescriptors = { expose: { dependencies: ['albumData', 'coverArtistContribsByRef'], - transform: ( - hasCoverArt, - {albumData, coverArtistContribsByRef, [Track.instance]: track} - ) => + transform: (hasCoverArt, { + albumData, + coverArtistContribsByRef, + [Track.instance]: track, + }) => Track.hasCoverArt( track, albumData, @@ -755,15 +748,12 @@ Track.propertyDescriptors = { expose: { dependencies: ['albumData', 'coverArtistContribsByRef'], - transform: ( - coverArtFileExtension, - { - albumData, - coverArtistContribsByRef, - hasCoverArt, - [Track.instance]: track, - } - ) => + transform: (coverArtFileExtension, { + albumData, + coverArtistContribsByRef, + hasCoverArt, + [Track.instance]: track, + }) => coverArtFileExtension ?? (Track.hasCoverArt( track, @@ -851,10 +841,11 @@ Track.propertyDescriptors = { expose: { dependencies: ['albumData', 'dateFirstReleased'], - transform: ( - coverArtDate, - {albumData, dateFirstReleased, [Track.instance]: track} - ) => + transform: (coverArtDate, { + albumData, + dateFirstReleased, + [Track.instance]: track, + }) => coverArtDate ?? dateFirstReleased ?? Track.findAlbum(track, albumData)?.trackArtDate ?? @@ -1691,9 +1682,7 @@ Object.assign(Language.prototype, { formatString(key, args = {}) { if (this.strings && !this.strings_htmlEscaped) { - throw new Error( - `HTML-escaped strings unavailable - please ensure escapeHTML function is provided` - ); + throw new Error(`HTML-escaped strings unavailable - please ensure escapeHTML function is provided`); } return this.formatStringHelper(this.strings_htmlEscaped, key, args); @@ -1780,12 +1769,7 @@ Object.assign(Language.prototype, { formatIndex(value) { this.assertIntlAvailable('intl_pluralOrdinal'); - return this.formatString( - 'count.index.' + this.intl_pluralOrdinal.select(value), - { - index: value, - } - ); + return this.formatString('count.index.' + this.intl_pluralOrdinal.select(value), {index: value}); }, formatNumber(value) { @@ -1803,10 +1787,7 @@ Object.assign(Language.prototype, { ? this.formatString('count.words.thousand', {words: num}) : this.formatString('count.words', {words: num}); - return this.formatString( - 'count.words.withUnit.' + this.getUnitForm(value), - {words} - ); + return this.formatString('count.words.withUnit.' + this.getUnitForm(value), {words}); }, // Conjunction list: A, B, and C diff --git a/src/data/validators.js b/src/data/validators.js index 8d922399..5c357c83 100644 --- a/src/data/validators.js +++ b/src/data/validators.js @@ -1,5 +1,3 @@ -/** @format */ - import {withAggregate} from '../util/sugar.js'; import {color, ENABLE_COLOR} from '../util/cli.js'; @@ -104,9 +102,7 @@ export function isInstance(value, constructor) { isObject(value); if (!(value instanceof constructor)) - throw new TypeError( - `Expected ${constructor.name}, got ${value.constructor.name}` - ); + throw new TypeError(`Expected ${constructor.name}, got ${value.constructor.name}`); return true; } @@ -142,9 +138,7 @@ function validateArrayItemsHelper(itemValidator) { throw new Error(`Expected validator to return true`); } } catch (error) { - error.message = `(index: ${color.green(index)}, item: ${inspect(item)}) ${ - error.message - }`; + error.message = `(index: ${color.green(index)}, item: ${inspect(item)}) ${error.message}`; throw error; } }; @@ -174,10 +168,8 @@ export function isColor(color) { isStringNonEmpty(color); if (color.startsWith('#')) { - if (![1 + 3, 1 + 4, 1 + 6, 1 + 8].includes(color.length)) - throw new TypeError( - `Expected #rgb, #rgba, #rrggbb, or #rrggbbaa, got length ${color.length}` - ); + if (![4, 5, 7, 9].includes(color.length)) + throw new TypeError(`Expected #rgb, #rgba, #rrggbb, or #rrggbbaa, got length ${color.length}`); if (/[^0-9a-fA-F]/.test(color.slice(1))) throw new TypeError(`Expected hexadecimal digits`); @@ -204,37 +196,26 @@ export function validateProperties(spec) { if (Array.isArray(object)) throw new TypeError(`Expected an object, got array`); - withAggregate( - {message: `Errors validating object properties`}, - ({call}) => { - for (const [specKey, specValidator] of specEntries) { - call(() => { - const value = object[specKey]; - try { - specValidator(value); - } catch (error) { - error.message = `(key: ${color.green(specKey)}, value: ${inspect( - value - )}) ${error.message}`; - throw error; - } - }); - } + withAggregate({message: `Errors validating object properties`}, ({call}) => { + for (const [specKey, specValidator] of specEntries) { + call(() => { + const value = object[specKey]; + try { + specValidator(value); + } catch (error) { + error.message = `(key: ${color.green(specKey)}, value: ${inspect(value)}) ${error.message}`; + throw error; + } + }); + } - const unknownKeys = Object.keys(object).filter( - (key) => !specKeys.includes(key) - ); - if (unknownKeys.length > 0) { - call(() => { - throw new Error( - `Unknown keys present (${ - unknownKeys.length - }): [${unknownKeys.join(', ')}]` - ); - }); - } + const unknownKeys = Object.keys(object).filter((key) => !specKeys.includes(key)); + if (unknownKeys.length > 0) { + call(() => { + throw new Error(`Unknown keys present (${unknownKeys.length}): [${unknownKeys.join(', ')}]`); + }); } - ); + }); return true; }; @@ -243,7 +224,9 @@ export function validateProperties(spec) { export const isContribution = validateProperties({ who: isArtistRef, what: (value) => - value === undefined || value === null || isStringNonEmpty(value), + value === undefined || + value === null || + isStringNonEmpty(value), }); export const isContributionList = validateArrayItems(isContribution); @@ -251,7 +234,9 @@ export const isContributionList = validateArrayItems(isContribution); export const isAdditionalFile = validateProperties({ title: isString, description: (value) => - value === undefined || value === null || isString(value), + value === undefined || + value === null || + isString(value), files: validateArrayItems(isString), }); @@ -274,9 +259,7 @@ export function isDirectory(directory) { isStringNonEmpty(directory); if (directory.match(/[^a-zA-Z0-9_-]/)) - throw new TypeError( - `Expected only letters, numbers, dash, and underscore, got "${directory}"` - ); + throw new TypeError(`Expected only letters, numbers, dash, and underscore, got "${directory}"`); return true; } @@ -331,16 +314,14 @@ export function validateReference(type = 'track') { if (!match) throw new TypeError(`Malformed reference`); - const { - groups: {typePart, directoryPart}, - } = match; + const {groups: {typePart, directoryPart}} = match; - if (typePart && typePart !== type) - throw new TypeError( - `Expected ref to begin with "${type}:", got "${typePart}:"` - ); + if (typePart) { + if (typePart !== type) + throw new TypeError(`Expected ref to begin with "${type}:", got "${typePart}:"`); - if (typePart) isDirectory(directoryPart); + isDirectory(directoryPart); + } isName(ref); @@ -381,9 +362,6 @@ export function oneOf(...checks) { error.check = check; errors.push(error); } - throw new AggregateError( - errors, - `Expected one of ${checks.length} possible checks, but none were true` - ); + throw new AggregateError(errors, `Expected one of ${checks.length} possible checks, but none were true`); }; } diff --git a/src/data/yaml.js b/src/data/yaml.js index e18b7334..2adce50b 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -1,5 +1,3 @@ -/** @format */ - // yaml.js - specification for HSMusic YAML data file format and utilities for // loading and processing YAML files and documents @@ -112,11 +110,8 @@ function makeProcessDocument( // Invert the property-field mapping, since it'll come in handy for // assigning update() source values later. const fieldPropertyMapping = Object.fromEntries( - Object.entries(propertyFieldMapping).map(([property, field]) => [ - field, - property, - ]) - ); + Object.entries(propertyFieldMapping) + .map(([property, field]) => [field, property])); const decorateErrorWithName = (fn) => { const nameField = propertyFieldMapping['name']; @@ -136,9 +131,8 @@ function makeProcessDocument( }; return decorateErrorWithName((document) => { - const documentEntries = Object.entries(document).filter( - ([field]) => !ignoredFields.includes(field) - ); + const documentEntries = Object.entries(document) + .filter(([field]) => !ignoredFields.includes(field)); const unknownFields = documentEntries .map(([field]) => field) @@ -167,22 +161,17 @@ function makeProcessDocument( const thing = Reflect.construct(thingClass, []); - withAggregate( - {message: `Errors applying ${color.green(thingClass.name)} properties`}, - ({call}) => { - for (const [property, value] of Object.entries(sourceProperties)) { - call(() => (thing[property] = value)); - } + withAggregate({message: `Errors applying ${color.green(thingClass.name)} properties`}, ({call}) => { + for (const [property, value] of Object.entries(sourceProperties)) { + call(() => (thing[property] = value)); } - ); + }); return thing; }); } -makeProcessDocument.UnknownFieldsError = class UnknownFieldsError extends ( - Error -) { +makeProcessDocument.UnknownFieldsError = class UnknownFieldsError extends Error { constructor(fields) { super(`Unknown fields present: ${fields.join(', ')}`); this.fields = fields; @@ -191,13 +180,13 @@ makeProcessDocument.UnknownFieldsError = class UnknownFieldsError extends ( export const processAlbumDocument = makeProcessDocument(Album, { fieldTransformations: { - Artists: parseContributors, + 'Artists': parseContributors, 'Cover Artists': parseContributors, 'Default Track Cover Artists': parseContributors, 'Wallpaper Artists': parseContributors, 'Banner Artists': parseContributors, - Date: (value) => new Date(value), + 'Date': (value) => new Date(value), 'Date Added': (value) => new Date(value), 'Cover Art Date': (value) => new Date(value), 'Default Track Cover Art Date': (value) => new Date(value), @@ -263,13 +252,13 @@ export const processTrackGroupDocument = makeProcessDocument(TrackGroup, { export const processTrackDocument = makeProcessDocument(Track, { fieldTransformations: { - Duration: getDurationInSeconds, + 'Duration': getDurationInSeconds, 'Date First Released': (value) => new Date(value), 'Cover Art Date': (value) => new Date(value), - Artists: parseContributors, - Contributors: parseContributors, + 'Artists': parseContributors, + 'Contributors': parseContributors, 'Cover Artists': parseContributors, 'Additional Files': parseAdditionalFiles, @@ -323,9 +312,9 @@ export const processArtistDocument = makeProcessDocument(Artist, { export const processFlashDocument = makeProcessDocument(Flash, { fieldTransformations: { - Date: (value) => new Date(value), + 'Date': (value) => new Date(value), - Contributors: parseContributors, + 'Contributors': parseContributors, }, propertyFieldMapping: { @@ -354,7 +343,7 @@ export const processFlashActDocument = makeProcessDocument(FlashAct, { export const processNewsEntryDocument = makeProcessDocument(NewsEntry, { fieldTransformations: { - Date: (value) => new Date(value), + 'Date': (value) => new Date(value), }, propertyFieldMapping: { @@ -421,16 +410,13 @@ export const processWikiInfoDocument = makeProcessDocument(WikiInfo, { }, }); -export const processHomepageLayoutDocument = makeProcessDocument( - HomepageLayout, - { - propertyFieldMapping: { - sidebarContent: 'Sidebar Content', - }, +export const processHomepageLayoutDocument = makeProcessDocument(HomepageLayout, { + propertyFieldMapping: { + sidebarContent: 'Sidebar Content', + }, - ignoredFields: ['Homepage'], - } -); + ignoredFields: ['Homepage'], +}); export function makeProcessHomepageLayoutRowDocument(rowClass, spec) { return makeProcessDocument(rowClass, { @@ -459,9 +445,8 @@ export const homepageLayoutRowTypeProcessMapping = { export function processHomepageLayoutRowDocument(document) { const type = document['Type']; - const match = Object.entries(homepageLayoutRowTypeProcessMapping).find( - ([key]) => key === type - ); + const match = Object.entries(homepageLayoutRowTypeProcessMapping) + .find(([key]) => key === type); if (!match) { throw new TypeError(`No processDocument function for row type ${type}!`); @@ -507,14 +492,9 @@ export function parseAdditionalFiles(array) { export function parseCommentary(text) { if (text) { - const lines = String(text).split('\n'); + const lines = String(text.trim()).split('\n'); if (!lines[0].replace(/<\/b>/g, '').includes(':</i>')) { - return { - error: `An entry is missing commentary citation: "${lines[0].slice( - 0, - 40 - )}..."`, - }; + throw new Error(`Missing commentary citation: "${lines[0].slice(0, 40)}..."`); } return text; } else { @@ -547,9 +527,7 @@ export function parseContributors(contributors) { const badContributor = contributors.find((val) => typeof val === 'string'); if (badContributor) { - return { - error: `An entry has an incorrectly formatted contributor, "${badContributor}".`, - }; + throw new Error(`Incorrectly formatted contribution: "${badContributor}".`); } if (contributors.length === 1 && contributors[0].who === 'none') { @@ -565,13 +543,17 @@ function parseDimensions(string) { } const parts = string.split(/[x,* ]+/g); - if (parts.length !== 2) - throw new Error(`Invalid dimensions: ${string} (expected width & height)`); + + if (parts.length !== 2) { + throw new Error(`Invalid dimensions: ${string} (expected "width & height")`); + } + const nums = parts.map((part) => Number(part.trim())); - if (nums.includes(NaN)) - throw new Error( - `Invalid dimensions: ${string} (couldn't parse as numbers)` - ); + + if (nums.includes(NaN)) { + throw new Error(`Invalid dimensions: ${string} (couldn't parse as numbers)`); + } + return nums; } @@ -671,7 +653,7 @@ export const dataSteps = [ files: async (dataPath) => ( await findFiles(path.join(dataPath, DATA_ALBUM_DIRECTORY), { - filter: f => path.extname(f) === '.yaml', + filter: (f) => path.extname(f) === '.yaml', joinParentDirectory: false, }) ).map(file => path.join(DATA_ALBUM_DIRECTORY, file)), @@ -759,16 +741,14 @@ export const dataSteps = [ const artistAliasData = results.flatMap((artist) => { const origRef = Thing.getReference(artist); - return ( - artist.aliasNames?.map((name) => { - const alias = new Artist(); - alias.name = name; - alias.isAlias = true; - alias.aliasedArtistRef = origRef; - alias.artistData = artistData; - return alias; - }) ?? [] - ); + return artist.aliasNames?.map((name) => { + const alias = new Artist(); + alias.name = name; + alias.isAlias = true; + alias.aliasedArtistRef = origRef; + alias.artistData = artistData; + return alias; + }) ?? []; }); return {artistData, artistAliasData}; @@ -856,9 +836,7 @@ export const dataSteps = [ } const groupData = results.filter((x) => x instanceof Group); - const groupCategoryData = results.filter( - (x) => x instanceof GroupCategory - ); + const groupCategoryData = results.filter((x) => x instanceof GroupCategory); return {groupData, groupCategoryData}; }, @@ -945,9 +923,7 @@ export async function loadAndProcessDataDocuments({dataPath}) { } catch (error) { error.message += (error.message.includes('\n') ? '\n' : ' ') + - `(file: ${color.bright( - color.blue(path.relative(dataPath, x.file)) - )})`; + `(file: ${color.bright(color.blue(path.relative(dataPath, x.file)))})`; throw error; } }; @@ -968,17 +944,14 @@ export async function loadAndProcessDataDocuments({dataPath}) { documentMode === documentModes.oneDocumentTotal ) { if (!dataStep.file) { - throw new Error( - `Expected 'file' property for ${documentMode.toString()}` - ); + throw new Error(`Expected 'file' property for ${documentMode.toString()}`); } const file = path.join( dataPath, typeof dataStep.file === 'function' ? await callAsync(dataStep.file, dataPath) - : dataStep.file - ); + : dataStep.file); const readResult = await callAsync(readFile, file, 'utf-8'); @@ -1005,8 +978,7 @@ export async function loadAndProcessDataDocuments({dataPath}) { const {result, aggregate} = mapAggregate( yamlResult, decorateErrorWithIndex(dataStep.processDocument), - {message: `Errors processing documents`} - ); + {message: `Errors processing documents`}); processResults = result; call(aggregate.close); } @@ -1023,9 +995,7 @@ export async function loadAndProcessDataDocuments({dataPath}) { } if (!dataStep.files) { - throw new Error( - `Expected 'files' property for ${documentMode.toString()}` - ); + throw new Error(`Expected 'files' property for ${documentMode.toString()}`); } let files = ( @@ -1042,8 +1012,7 @@ export async function loadAndProcessDataDocuments({dataPath}) { const readResults = await mapAsync( files, - (file) => - readFile(file, 'utf-8').then((contents) => ({file, contents})), + (file) => readFile(file, 'utf-8').then((contents) => ({file, contents})), {message: `Errors reading data files`} ); @@ -1059,82 +1028,76 @@ export async function loadAndProcessDataDocuments({dataPath}) { let processResults; if (documentMode === documentModes.headerAndEntries) { - nest( - {message: `Errors processing data files as valid documents`}, - ({call, map}) => { - processResults = []; - - yamlResults.forEach(({file, documents}) => { - const [headerDocument, ...entryDocuments] = documents; - - const header = call( - decorateErrorWithFile(({document}) => - dataStep.processHeaderDocument(document) - ), - {file, document: headerDocument} - ); - - // Don't continue processing files whose header - // document is invalid - the entire file is excempt - // from data in this case. - if (!header) { - return; - } - - const entries = map( - entryDocuments.map((document) => ({file, document})), - decorateErrorWithFile( - decorateErrorWithIndex(({document}) => - dataStep.processEntryDocument(document) - ) - ), - {message: `Errors processing entry documents`} - ); + nest({message: `Errors processing data files as valid documents`}, ({call, map}) => { + processResults = []; + + yamlResults.forEach(({file, documents}) => { + const [headerDocument, ...entryDocuments] = documents; + + const header = call( + decorateErrorWithFile(({document}) => + dataStep.processHeaderDocument(document) + ), + {file, document: headerDocument} + ); + + // Don't continue processing files whose header + // document is invalid - the entire file is excempt + // from data in this case. + if (!header) { + return; + } - // Entries may be incomplete (i.e. any errored - // documents won't have a processed output - // represented here) - this is intentional! By - // principle, partial output is preferred over - // erroring an entire file. - processResults.push({header, entries}); - }); - } - ); + const entries = map( + entryDocuments.map((document) => ({file, document})), + decorateErrorWithFile( + decorateErrorWithIndex(({document}) => + dataStep.processEntryDocument(document) + ) + ), + {message: `Errors processing entry documents`} + ); + + // Entries may be incomplete (i.e. any errored + // documents won't have a processed output + // represented here) - this is intentional! By + // principle, partial output is preferred over + // erroring an entire file. + processResults.push({header, entries}); + }); + }); } if (documentMode === documentModes.onePerFile) { - nest( - {message: `Errors processing data files as valid documents`}, - ({call}) => { - processResults = []; - - yamlResults.forEach(({file, documents}) => { - if (documents.length > 1) { - call( - decorateErrorWithFile(() => { - throw new Error( - `Only expected one document to be present per file` - ); - }) - ); - return; - } - - const result = call( - decorateErrorWithFile(({document}) => - dataStep.processDocument(document) - ), - {file, document: documents[0]} + nest({message: `Errors processing data files as valid documents`}, ({call}) => { + processResults = []; + + yamlResults.forEach(({file, documents}) => { + if (documents.length > 1) { + call( + decorateErrorWithFile(() => { + throw new Error( + `Only expected one document to be present per file` + ); + }) ); + return; + } - if (!result) { - return; - } + const result = call( + decorateErrorWithFile(({document}) => + dataStep.processDocument(document) + ), + {file, document: documents[0]} + ); - processResults.push(result); - }); - } - ); + if (!result) { + return; + } + + processResults.push(result); + }); + }); } const saveResult = call(dataStep.save, processResults); @@ -1158,9 +1121,10 @@ export async function loadAndProcessDataDocuments({dataPath}) { export function linkWikiDataArrays(wikiData) { function assignWikiData(things, ...keys) { for (let i = 0; i < things.length; i++) { + const thing = things[i]; for (let j = 0; j < keys.length; j++) { const key = keys[j]; - things[i][key] = wikiData[key]; + thing[key] = wikiData[key]; } } } @@ -1169,32 +1133,11 @@ export function linkWikiDataArrays(wikiData) { assignWikiData([WD.wikiInfo], 'groupData'); - assignWikiData( - WD.albumData, - 'artistData', - 'artTagData', - 'groupData', - 'trackData' - ); - WD.albumData.forEach((album) => - assignWikiData(album.trackGroups, 'trackData') - ); - - assignWikiData( - WD.trackData, - 'albumData', - 'artistData', - 'artTagData', - 'flashData', - 'trackData' - ); - assignWikiData( - WD.artistData, - 'albumData', - 'artistData', - 'flashData', - 'trackData' - ); + assignWikiData(WD.albumData, 'artistData', 'artTagData', 'groupData', 'trackData'); + WD.albumData.forEach((album) => assignWikiData(album.trackGroups, 'trackData')); + + assignWikiData(WD.trackData, 'albumData', 'artistData', 'artTagData', 'flashData', 'trackData'); + assignWikiData(WD.artistData, 'albumData', 'artistData', 'flashData', 'trackData'); assignWikiData(WD.groupData, 'albumData', 'groupCategoryData'); assignWikiData(WD.groupCategoryData, 'groupData'); assignWikiData(WD.flashData, 'artistData', 'flashActData', 'trackData'); @@ -1236,48 +1179,47 @@ export function filterDuplicateDirectories(wikiData) { const aggregate = openAggregate({message: `Duplicate directories found`}); for (const thingDataProp of deduplicateSpec) { const thingData = wikiData[thingDataProp]; - aggregate.nest( - { - message: `Duplicate directories found in ${color.green( - 'wikiData.' + thingDataProp - )}`, - }, - ({call}) => { - const directoryPlaces = Object.create(null); - const duplicateDirectories = []; - for (const thing of thingData) { - const {directory} = thing; - if (directory in directoryPlaces) { - directoryPlaces[directory].push(thing); - duplicateDirectories.push(directory); - } else { - directoryPlaces[directory] = [thing]; - } + aggregate.nest({message: `Duplicate directories found in ${color.green('wikiData.' + thingDataProp)}`}, ({call}) => { + const directoryPlaces = Object.create(null); + const duplicateDirectories = []; + + for (const thing of thingData) { + const {directory} = thing; + if (directory in directoryPlaces) { + directoryPlaces[directory].push(thing); + duplicateDirectories.push(directory); + } else { + directoryPlaces[directory] = [thing]; } - if (empty(duplicateDirectories)) return; - duplicateDirectories.sort((a, b) => { - const aL = a.toLowerCase(); - const bL = b.toLowerCase(); - return aL < bL ? -1 : aL > bL ? 1 : 0; + } + + if (empty(duplicateDirectories)) return; + + duplicateDirectories.sort((a, b) => { + const aL = a.toLowerCase(); + const bL = b.toLowerCase(); + return aL < bL ? -1 : aL > bL ? 1 : 0; + }); + + for (const directory of duplicateDirectories) { + const places = directoryPlaces[directory]; + call(() => { + throw new Error( + `Duplicate directory ${color.green(directory)}:\n` + + places.map((thing) => ` - ` + inspect(thing)).join('\n') + ); }); - for (const directory of duplicateDirectories) { - const places = directoryPlaces[directory]; - call(() => { - throw new Error( - `Duplicate directory ${color.green(directory)}:\n` + - places.map((thing) => ` - ` + inspect(thing)).join('\n') - ); - }); - } - const allDuplicatedThings = Object.values(directoryPlaces) - .filter((arr) => arr.length > 1) - .flat(); - const filteredThings = thingData.filter( - (thing) => !allDuplicatedThings.includes(thing) - ); - wikiData[thingDataProp] = filteredThings; } - ); + + const allDuplicatedThings = Object.values(directoryPlaces) + .filter((arr) => arr.length > 1) + .flat(); + + const filteredThings = thingData + .filter((thing) => !allDuplicatedThings.includes(thing)); + + wikiData[thingDataProp] = filteredThings; + }); } // TODO: This code closes the aggregate but it generally gets closed again @@ -1303,67 +1245,46 @@ export function filterDuplicateDirectories(wikiData) { // data array. export function filterReferenceErrors(wikiData) { const referenceSpec = [ - [ - 'wikiInfo', - { - divideTrackListsByGroupsByRef: 'group', - }, - ], - - [ - 'albumData', - { - artistContribsByRef: '_contrib', - coverArtistContribsByRef: '_contrib', - trackCoverArtistContribsByRef: '_contrib', - wallpaperArtistContribsByRef: '_contrib', - bannerArtistContribsByRef: '_contrib', - groupsByRef: 'group', - artTagsByRef: 'artTag', - }, - ], - - [ - 'trackData', - { - artistContribsByRef: '_contrib', - contributorContribsByRef: '_contrib', - coverArtistContribsByRef: '_contrib', - referencedTracksByRef: 'track', - artTagsByRef: 'artTag', - originalReleaseTrackByRef: 'track', - }, - ], - - [ - 'groupCategoryData', - { - groupsByRef: 'group', - }, - ], - - [ - 'homepageLayout.rows', - { - sourceGroupsByRef: 'group', - sourceAlbumsByRef: 'album', - }, - ], - - [ - 'flashData', - { - contributorContribsByRef: '_contrib', - featuredTracksByRef: 'track', - }, - ], - - [ - 'flashActData', - { - flashesByRef: 'flash', - }, - ], + ['wikiInfo', { + divideTrackListsByGroupsByRef: 'group', + }], + + ['albumData', { + artistContribsByRef: '_contrib', + coverArtistContribsByRef: '_contrib', + trackCoverArtistContribsByRef: '_contrib', + wallpaperArtistContribsByRef: '_contrib', + bannerArtistContribsByRef: '_contrib', + groupsByRef: 'group', + artTagsByRef: 'artTag', + }], + + ['trackData', { + artistContribsByRef: '_contrib', + contributorContribsByRef: '_contrib', + coverArtistContribsByRef: '_contrib', + referencedTracksByRef: 'track', + artTagsByRef: 'artTag', + originalReleaseTrackByRef: 'track', + }], + + ['groupCategoryData', { + groupsByRef: 'group', + }], + + ['homepageLayout.rows', { + sourceGroupsByRef: 'group', + sourceAlbumsByRef: 'album', + }], + + ['flashData', { + contributorContribsByRef: '_contrib', + featuredTracksByRef: 'track', + }], + + ['flashActData', { + flashesByRef: 'flash', + }], ]; function getNestedProp(obj, key) { @@ -1373,94 +1294,56 @@ export function filterReferenceErrors(wikiData) { return recursive(obj, keys); } - const aggregate = openAggregate({ - message: `Errors validating between-thing references in data`, - }); + const aggregate = openAggregate({message: `Errors validating between-thing references in data`}); const boundFind = bindFind(wikiData, {mode: 'error'}); for (const [thingDataProp, propSpec] of referenceSpec) { const thingData = getNestedProp(wikiData, thingDataProp); - aggregate.nest( - { - message: `Reference errors in ${color.green( - 'wikiData.' + thingDataProp - )}`, - }, - ({nest}) => { - const things = Array.isArray(thingData) ? thingData : [thingData]; - for (const thing of things) { - nest( - {message: `Reference errors in ${inspect(thing)}`}, - ({filter}) => { - for (const [property, findFnKey] of Object.entries(propSpec)) { - if (!thing[property]) continue; - if (findFnKey === '_contrib') { - thing[property] = filter( - thing[property], - decorateErrorWithIndex(({who}) => { - const alias = find.artist(who, wikiData.artistAliasData, { - mode: 'quiet', - }); - if (alias) { - const original = find.artist( - alias.aliasedArtistRef, - wikiData.artistData, - { - mode: 'quiet', - } - ); - throw new Error( - `Reference ${color.red( - who - )} is to an alias, should be ${color.green( - original.name - )}` - ); - } - return boundFind.artist(who); - }), - { - message: `Reference errors in contributions ${color.green( - property - )} (${color.green('find.artist')})`, - } - ); - continue; - } - const findFn = boundFind[findFnKey]; - const value = thing[property]; - if (Array.isArray(value)) { - thing[property] = filter( - value, - decorateErrorWithIndex(findFn), - { - message: `Reference errors in property ${color.green( - property - )} (${color.green('find.' + findFnKey)})`, - } - ); - } else { - nest( - { - message: `Reference error in property ${color.green( - property - )} (${color.green('find.' + findFnKey)})`, - }, - ({call}) => { - try { - call(findFn, value); - } catch (error) { - thing[property] = null; - throw error; - } - } - ); + + aggregate.nest({message: `Reference errors in ${color.green('wikiData.' + thingDataProp)}`}, ({nest}) => { + const things = Array.isArray(thingData) ? thingData : [thingData]; + + for (const thing of things) { + nest({message: `Reference errors in ${inspect(thing)}`}, ({filter}) => { + for (const [property, findFnKey] of Object.entries(propSpec)) { + if (!thing[property]) continue; + + if (findFnKey === '_contrib') { + thing[property] = filter( + thing[property], + decorateErrorWithIndex(({who}) => { + const alias = find.artist(who, wikiData.artistAliasData, {mode: 'quiet'}); + if (alias) { + const original = find.artist(alias.aliasedArtistRef, wikiData.artistData, {mode: 'quiet'}); + throw new Error(`Reference ${color.red(who)} is to an alias, should be ${color.green(original.name)}`); + } + return boundFind.artist(who); + }), + {message: `Reference errors in contributions ${color.green(property)} (${color.green('find.artist')})`}); + continue; + } + + const findFn = boundFind[findFnKey]; + const value = thing[property]; + + if (Array.isArray(value)) { + thing[property] = filter( + value, + decorateErrorWithIndex(findFn), + {message: `Reference errors in property ${color.green(property)} (${color.green('find.' + findFnKey)})`}); + } else { + nest({message: `Reference error in property ${color.green(property)} (${color.green('find.' + findFnKey)})`}, ({call}) => { + try { + call(findFn, value); + } catch (error) { + thing[property] = null; + throw error; } - } + }); } - ); - } + } + }); } - ); + }); } return aggregate; @@ -1472,18 +1355,15 @@ export function filterReferenceErrors(wikiData) { // a boilerplate for more specialized output, or as a quick start in utilities // where reporting info about data loading isn't as relevant as during the // main wiki build process. -export async function quickLoadAllFromYAML( - dataPath, - {showAggregate: customShowAggregate = showAggregate} = {} -) { +export async function quickLoadAllFromYAML(dataPath, { + showAggregate: customShowAggregate = showAggregate, +} = {}) { const showAggregate = customShowAggregate; let wikiData; { - const {aggregate, result} = await loadAndProcessDataDocuments({ - dataPath, - }); + const {aggregate, result} = await loadAndProcessDataDocuments({dataPath}); wikiData = result; diff --git a/src/file-size-preloader.js b/src/file-size-preloader.js index 363fb4c0..ca1452d0 100644 --- a/src/file-size-preloader.js +++ b/src/file-size-preloader.js @@ -1,5 +1,3 @@ -/** @format */ - // Very simple, bare-bones file size loader which takes a bunch of file // paths, gets their filesizes, and resolves a promise when it's done. // diff --git a/src/gen-thumbs.js b/src/gen-thumbs.js index 9151201f..dc1f6fb4 100644 --- a/src/gen-thumbs.js +++ b/src/gen-thumbs.js @@ -1,5 +1,4 @@ #!/usr/bin/env node -/** @format */ // Ok, so the d8te is 3 March 2021, and the music wiki was initially released // on 15 November 2019. That is 474 days or 11376 hours. In my opinion, and @@ -98,10 +97,10 @@ import {commandExists, isMain, promisifyProcess} from './util/node-utils.js'; import {delay, queue} from './util/sugar.js'; -function traverse( - startDirPath, - {filterFile = () => true, filterDir = () => true} = {} -) { +function traverse(startDirPath, { + filterFile = () => true, + filterDir = () => true +} = {}) { const recursive = (names, subDirPath) => Promise.all( names.map((name) => @@ -197,10 +196,10 @@ function generateImageThumbnails(filePath, {spawnConvert}) { ]); } -export default async function genThumbs( - mediaPath, - {queueSize = 0, quiet = false} = {} -) { +export default async function genThumbs(mediaPath, { + queueSize = 0, + quiet = false, +} = {}) { if (!mediaPath) { throw new Error('Expected mediaPath to be passed'); } diff --git a/src/listing-spec.js b/src/listing-spec.js index e6cd7a04..2e129ff4 100644 --- a/src/listing-spec.js +++ b/src/listing-spec.js @@ -1,5 +1,3 @@ -/** @format */ - import { empty, accumulateSum, diff --git a/src/misc-templates.js b/src/misc-templates.js index c6275336..2614aac9 100644 --- a/src/misc-templates.js +++ b/src/misc-templates.js @@ -1,5 +1,3 @@ -/** @format */ - // Miscellaneous utility functions which are useful across page specifications. // These are made available right on a page spec's ({wikiData, language, ...}) // args object! @@ -163,9 +161,7 @@ function unbound_generateChronologyLinks(currentThing, { } if (contributions.length > 8) { - return `<div class="chronology">${language.$( - 'misc.chronology.seeArtistPages' - )}</div>`; + return `<div class="chronology">${language.$('misc.chronology.seeArtistPages')}</div>`; } return contributions @@ -789,4 +785,4 @@ export { unbound_generateNavigationLinks as generateNavigationLinks, unbound_getFooterLocalizationLinks as getFooterLocalizationLinks, -} \ No newline at end of file +} diff --git a/src/page/album-commentary.js b/src/page/album-commentary.js index e3a63baf..a0ac8d94 100644 --- a/src/page/album-commentary.js +++ b/src/page/album-commentary.js @@ -1,5 +1,3 @@ -/** @format */ - // Album commentary page and index specifications. import {filterAlbumsByCommentary} from '../util/wiki-data.js'; diff --git a/src/page/album.js b/src/page/album.js index 14d4a9d2..009ed55d 100644 --- a/src/page/album.js +++ b/src/page/album.js @@ -1,5 +1,3 @@ -/** @format */ - // Album page specification. import { @@ -30,6 +28,7 @@ export function write(album, {wikiData}) { duration: language.formatDuration(track.duration ?? 0), track: link.track(track), }; + return html.tag('li', {style: getLinkThemeString(track.color)}, compareArrays( diff --git a/src/page/artist-alias.js b/src/page/artist-alias.js index 3d882f65..e2b16046 100644 --- a/src/page/artist-alias.js +++ b/src/page/artist-alias.js @@ -1,5 +1,3 @@ -/** @format */ - // Artist alias redirect pages. // (Makes old permalinks bring visitors to the up-to-date page.) diff --git a/src/page/artist.js b/src/page/artist.js index f6a81f67..1b5a5060 100644 --- a/src/page/artist.js +++ b/src/page/artist.js @@ -1,5 +1,3 @@ -/** @format */ - // Artist page specification. // // NB: See artist-alias.js for artist alias redirect pages. @@ -161,16 +159,13 @@ export function write(artist, {wikiData}) { ? language.$('artistPage.creditList.entry.rerelease', {entry}) : !empty(artists) ? contrib.what || contrib.whatArray?.length - ? language.$( - 'artistPage.creditList.entry.withArtists.withContribution', - { - entry, - artists: getArtistString(artists), - contribution: contrib.whatArray - ? language.formatUnitList(contrib.whatArray) - : contrib.what, - } - ) + ? language.$('artistPage.creditList.entry.withArtists.withContribution', { + entry, + artists: getArtistString(artists), + contribution: contrib.whatArray + ? language.formatUnitList(contrib.whatArray) + : contrib.what, + }) : language.$('artistPage.creditList.entry.withArtists', { entry, artists: getArtistString(artists), @@ -227,15 +222,12 @@ export function write(artist, {wikiData}) { original: track.originalReleaseTrack, entry: language.$('artistPage.creditList.entry.track.withDuration', { track: link.track(track), - duration: language.formatDuration( - track.duration ?? 0 - ), + duration: language.formatDuration(track.duration ?? 0), }), ...props, })) .map(({original, ...opts}) => - html.tag( - 'li', + html.tag('li', {class: original && 'rerelease'}, generateEntryAccents({ getArtistString, @@ -282,20 +274,14 @@ export function write(artist, {wikiData}) { type: 'data', path: ['artist', artist.directory], data: ({serializeContribs, serializeLink}) => { - const serializeArtistsAndContrib = bindOpts( - unbound_serializeArtistsAndContrib, - { - serializeContribs, - serializeLink, - } - ); - - const serializeTrackListChunks = bindOpts( - unbound_serializeTrackListChunks, - { - serializeLink, - } - ); + const serializeArtistsAndContrib = bindOpts(unbound_serializeArtistsAndContrib, { + serializeContribs, + serializeLink, + }); + + const serializeTrackListChunks = bindOpts(unbound_serializeTrackListChunks, { + serializeLink, + }); return { albums: { @@ -663,12 +649,12 @@ export function write(artist, {wikiData}) { // Utility functions -function generateNavForArtist( - artist, - isGallery, - hasGallery, - {generateInfoGalleryLinks, link, language, wikiData} -) { +function generateNavForArtist(artist, isGallery, hasGallery, { + generateInfoGalleryLinks, + language, + link, + wikiData, +}) { const {wikiInfo} = wikiData; const infoGalleryLinks = diff --git a/src/page/flash.js b/src/page/flash.js index 237dd47f..74a6b4aa 100644 --- a/src/page/flash.js +++ b/src/page/flash.js @@ -1,5 +1,3 @@ -/** @format */ - // Flash page and index specifications. import {empty} from '../util/sugar.js'; diff --git a/src/page/group.js b/src/page/group.js index 2bd6da96..c261565b 100644 --- a/src/page/group.js +++ b/src/page/group.js @@ -1,5 +1,3 @@ -/** @format */ - // Group page specifications. import { diff --git a/src/page/index.js b/src/page/index.js index 149503f0..f580cbea 100644 --- a/src/page/index.js +++ b/src/page/index.js @@ -1,5 +1,3 @@ -/** @format */ - // NB: This is the index for the page/ directory and contains exports for all // other modules here! It's not the page spec for the homepage - see // homepage.js for that. diff --git a/src/page/listing.js b/src/page/listing.js index 65982f83..cb297a89 100644 --- a/src/page/listing.js +++ b/src/page/listing.js @@ -1,5 +1,3 @@ -/** @format */ - // Listing page specification. // // The targets here are a bit different than for most pages: rather than data diff --git a/src/page/static.js b/src/page/static.js index 8925b606..2a0f5e53 100644 --- a/src/page/static.js +++ b/src/page/static.js @@ -1,5 +1,3 @@ -/** @format */ - // Static content page specification. (These are static pages coded into the // wiki data folder, used for a variety of purposes, e.g. wiki info, // changelog, and so on.) diff --git a/src/page/tag.js b/src/page/tag.js index faa0df22..da4f194a 100644 --- a/src/page/tag.js +++ b/src/page/tag.js @@ -1,5 +1,3 @@ -/** @format */ - // Art tag page specification. export function condition({wikiData}) { @@ -28,8 +26,8 @@ export function write(tag, {wikiData}) { getThemeString, getTrackCover, html, - link, language, + link, }) => ({ title: language.$('tagPage.title', {tag: tag.name}), theme: getThemeString(tag.color), @@ -79,10 +77,11 @@ export function write(tag, {wikiData}) { // Utility functions -function generateTagNav( - tag, - {link, language, wikiData} -) { +function generateTagNav(tag, { + language, + link, + wikiData, +}) { return { linkContainerClasses: ['nav-links-hierarchy'], links: [ diff --git a/src/page/track.js b/src/page/track.js index cf937248..b61defe2 100644 --- a/src/page/track.js +++ b/src/page/track.js @@ -1,5 +1,3 @@ -/** @format */ - // Track page specification. import { @@ -64,7 +62,7 @@ export function write(track, {wikiData}) { const hasCommentary = track.commentary || otherReleases.some((t) => t.commentary); - const generateCommentary = ({link, language, transformMultiline}) => + const generateCommentary = ({language, link, transformMultiline}) => transformMultiline([ track.commentary, ...otherReleases.map((track) => diff --git a/src/repl.js b/src/repl.js index bd447bec..5497ef55 100644 --- a/src/repl.js +++ b/src/repl.js @@ -1,5 +1,3 @@ -/** @format */ - import * as os from 'os'; import * as path from 'path'; import * as repl from 'repl'; diff --git a/src/static/client.js b/src/static/client.js index 1ffcb939..32fb2abe 100644 --- a/src/static/client.js +++ b/src/static/client.js @@ -1,5 +1,3 @@ -/** @format */ - // This is the JS file that gets loaded on the client! It's only really used for // the random track feature right now - the idea is we only use it for stuff // that cannot 8e done at static-site compile time, 8y its fundamentally @@ -392,8 +390,7 @@ function makeInfoCardLinkHandlers(type) { fastHover = true; infoCard.show(type, evt.target); }, - fastHover ? FAST_HOVER_INFO_DELAY : NORMAL_HOVER_INFO_DELAY - ); + fastHover ? FAST_HOVER_INFO_DELAY : NORMAL_HOVER_INFO_DELAY); clearTimeout(endFastHoverTimeout); endFastHoverTimeout = null; diff --git a/src/static/lazy-loading.js b/src/static/lazy-loading.js index 1b779d26..b5b0a368 100644 --- a/src/static/lazy-loading.js +++ b/src/static/lazy-loading.js @@ -1,5 +1,3 @@ -/** @format */ - // Lazy loading! Roll your own. Woot. // This file includes a 8unch of fall8acks and stuff like that, and is written // with fairly Olden JavaScript(TM), so as to work on pretty much any 8rowser diff --git a/src/upd8.js b/src/upd8.js index 44cbce05..8e3e0920 100755 --- a/src/upd8.js +++ b/src/upd8.js @@ -1,5 +1,4 @@ #!/usr/bin/env node -/** @format */ // HEY N8RDS! // @@ -814,8 +813,8 @@ function validateWriteObject(obj) { /* async function writeData(subKey, directory, data) { - const paths = writePage.paths('', 'data.' + subKey, directory, {file: 'data.json'}); - await writePage.write(JSON.stringify(data), {paths}); + const paths = writePage.paths('', 'data.' + subKey, directory, {file: 'data.json'}); + await writePage.write(JSON.stringify(data), {paths}); } */ @@ -865,20 +864,17 @@ writePage.to = return path; }; -writePage.html = ( - pageInfo, - { - defaultLanguage, - language, - languages, - localizedPaths, - paths, - oEmbedJSONHref, - to, - transformMultiline, - wikiData, - } -) => { +writePage.html = (pageInfo, { + defaultLanguage, + language, + languages, + localizedPaths, + paths, + oEmbedJSONHref, + to, + transformMultiline, + wikiData, +}) => { const {wikiInfo} = wikiData; let { @@ -986,10 +982,13 @@ writePage.html = ( }), ]); - const generateSidebarHTML = ( - id, - {content, multiple, classes, collapse = true, wide = false} - ) => + const generateSidebarHTML = (id, { + content, + multiple, + classes, + collapse = true, + wide = false, + }) => content ? html.tag('div', { @@ -1388,12 +1387,9 @@ writePage.write = async ({html, oEmbedJSON = '', paths}) => { }; // TODO: This only supports one <>-style argument. -writePage.paths = ( - baseDirectory, - fullKey, - directory = '', - {file = 'index.html'} = {} -) => { +writePage.paths = (baseDirectory, fullKey, directory = '', { + file = 'index.html', +} = {}) => { const [groupKey, subKey] = fullKey.split('.'); const pathname = @@ -1485,49 +1481,46 @@ function writeSharedFilesAndPages({language, wikiData}) { await writeFile(path.join(outputPath, from, 'index.html'), content); }; - return progressPromiseAll( - `Writing files & pages shared across languages.`, - [ - groupData?.some((group) => group.directory === 'fandom') && - redirect( - 'Fandom - Gallery', - 'albums/fandom', - 'localized.groupGallery', - 'fandom' - ), + return progressPromiseAll(`Writing files & pages shared across languages.`, [ + groupData?.some((group) => group.directory === 'fandom') && + redirect( + 'Fandom - Gallery', + 'albums/fandom', + 'localized.groupGallery', + 'fandom' + ), - groupData?.some((group) => group.directory === 'official') && - redirect( - 'Official - Gallery', - 'albums/official', - 'localized.groupGallery', - 'official' - ), + groupData?.some((group) => group.directory === 'official') && + redirect( + 'Official - Gallery', + 'albums/official', + 'localized.groupGallery', + 'official' + ), - wikiInfo.enableListings && - redirect( - 'Album Commentary', - 'list/all-commentary', - 'localized.commentaryIndex', - '' - ), + wikiInfo.enableListings && + redirect( + 'Album Commentary', + 'list/all-commentary', + 'localized.commentaryIndex', + '' + ), - writeFile( - path.join(outputPath, 'data.json'), - ( - '{\n' + - [ - `"albumData": ${stringifyThings(wikiData.albumData)},`, - wikiInfo.enableFlashesAndGames && - `"flashData": ${stringifyThings(wikiData.flashData)},`, - `"artistData": ${stringifyThings(wikiData.artistData)}`, - ] - .filter(Boolean) - .map(line => ' ' + line) - .join('\n') + - '\n}')), - ].filter(Boolean) - ); + writeFile( + path.join(outputPath, 'data.json'), + ( + '{\n' + + [ + `"albumData": ${stringifyThings(wikiData.albumData)},`, + wikiInfo.enableFlashesAndGames && + `"flashData": ${stringifyThings(wikiData.flashData)},`, + `"artistData": ${stringifyThings(wikiData.artistData)}`, + ] + .filter(Boolean) + .map(line => ' ' + line) + .join('\n') + + '\n}')), + ].filter(Boolean)); } function generateRedirectPage(title, target, {language}) { @@ -1752,10 +1745,7 @@ async function main() { } }; error(!dataPath, `Expected --data-path option or HSMUSIC_DATA to be set`); - error( - !mediaPath, - `Expected --media-path option or HSMUSIC_MEDIA to be set` - ); + error(!mediaPath, `Expected --media-path option or HSMUSIC_MEDIA to be set`); error(!outputPath, `Expected --out-path option or HSMUSIC_OUT to be set`); if (errored) { return; @@ -1833,9 +1823,7 @@ async function main() { { const logThings = (thingDataProp, label) => - logInfo` - ${ - wikiData[thingDataProp]?.length ?? color.red('(Missing!)') - } ${color.normal(color.dim(label))}`; + logInfo` - ${wikiData[thingDataProp]?.length ?? color.red('(Missing!)')} ${color.normal(color.dim(label))}`; try { logInfo`Loaded data and processed objects:`; logThings('albumData', 'albums'); @@ -2032,10 +2020,8 @@ async function main() { { const tagRefs = new Set( - [...WD.trackData, ...WD.albumData].flatMap( - (thing) => thing.artTagsByRef ?? [] - ) - ); + [...WD.trackData, ...WD.albumData] + .flatMap((thing) => thing.artTagsByRef ?? [])); for (const ref of tagRefs) { if (find.artTag(ref, WD.artTagData)) { @@ -2051,12 +2037,10 @@ async function main() { } } - WD.officialAlbumData = WD.albumData.filter((album) => - album.groups.some((group) => group.directory === OFFICIAL_GROUP_DIRECTORY) - ); - WD.fandomAlbumData = WD.albumData.filter((album) => - album.groups.every((group) => group.directory !== OFFICIAL_GROUP_DIRECTORY) - ); + WD.officialAlbumData = WD.albumData + .filter((album) => album.groups.some((group) => group.directory === OFFICIAL_GROUP_DIRECTORY)); + WD.fandomAlbumData = WD.albumData + .filter((album) => album.groups.every((group) => group.directory !== OFFICIAL_GROUP_DIRECTORY)); const fileSizePreloader = new FileSizePreloader(); @@ -2089,7 +2073,7 @@ async function main() { ]; const getSizeOfAdditionalFile = (mediaPath) => { - const {device = null} = + const {device} = additionalFilePaths.find(({media}) => media === mediaPath) || {}; if (!device) return null; return fileSizePreloader.getSizeOfPath(device); @@ -2097,9 +2081,7 @@ async function main() { logInfo`Preloading filesizes for ${additionalFilePaths.length} additional files...`; - fileSizePreloader.loadPaths( - ...additionalFilePaths.map((path) => path.device) - ); + fileSizePreloader.loadPaths(...additionalFilePaths.map((path) => path.device)); await fileSizePreloader.waitUntilDoneLoading(); logInfo`Done preloading filesizes!`; @@ -2139,18 +2121,14 @@ async function main() { } if (!pageSpec.write) { - logError`${flag + '.targets'} is specified, but ${ - flag + '.write' - } is missing!`; + logError`${flag + '.targets'} is specified, but ${flag + '.write'} is missing!`; error = true; return null; } const targets = pageSpec.targets({wikiData}); if (!Array.isArray(targets)) { - logError`${ - flag + '.targets' - } was called, but it didn't return an array! (${typeof targets})`; + logError`${flag + '.targets'} was called, but it didn't return an array! (${typeof targets})`; error = true; return null; } @@ -2230,345 +2208,333 @@ async function main() { } /* - await progressPromiseAll(`Writing data files shared across languages.`, queue( - dataWrites.map(({path, data}) => () => { - const bound = {}; + await progressPromiseAll(`Writing data files shared across languages.`, queue( + dataWrites.map(({path, data}) => () => { + const bound = {}; - bound.serializeLink = bindOpts(serializeLink, {}); + bound.serializeLink = bindOpts(serializeLink, {}); - bound.serializeContribs = bindOpts(serializeContribs, {}); + bound.serializeContribs = bindOpts(serializeContribs, {}); - bound.serializeImagePaths = bindOpts(serializeImagePaths, { - thumb - }); + bound.serializeImagePaths = bindOpts(serializeImagePaths, { + thumb + }); - bound.serializeCover = bindOpts(serializeCover, { - [bindOpts.bindIndex]: 2, - serializeImagePaths: bound.serializeImagePaths, - urls - }); + bound.serializeCover = bindOpts(serializeCover, { + [bindOpts.bindIndex]: 2, + serializeImagePaths: bound.serializeImagePaths, + urls + }); - bound.serializeGroupsForAlbum = bindOpts(serializeGroupsForAlbum, { - serializeLink - }); + bound.serializeGroupsForAlbum = bindOpts(serializeGroupsForAlbum, { + serializeLink + }); - bound.serializeGroupsForTrack = bindOpts(serializeGroupsForTrack, { - serializeLink - }); + bound.serializeGroupsForTrack = bindOpts(serializeGroupsForTrack, { + serializeLink + }); - // TODO: This only supports one <>-style argument. - return writeData(path[0], path[1], data({ - ...bound - })); - }), - queueSize - )); - */ + // TODO: This only supports one <>-style argument. + return writeData(path[0], path[1], data({...bound})); + }), + queueSize + )); + */ const perLanguageFn = async (language, i, entries) => { const baseDirectory = language === finalDefaultLanguage ? '' : language.code; - console.log( - `\x1b[34;1m${`[${i + 1}/${entries.length}] ${ - language.code - } (-> /${baseDirectory}) `.padEnd(60, '-')}\x1b[0m` - ); + console.log(`\x1b[34;1m${`[${i + 1}/${entries.length}] ${language.code} (-> /${baseDirectory}) `.padEnd(60, '-')}\x1b[0m`); + + await progressPromiseAll(`Writing ${language.code}`, queue([ + ...pageWrites.map((props) => () => { + const {path, page} = props; + + // TODO: This only supports one <>-style argument. + const pageSubKey = path[0]; + const directory = path[1]; + + const localizedPaths = Object.fromEntries( + Object.entries(languages) + .filter( + ([key, language]) => key !== 'default' && !language.hidden + ) + .map(([_key, language]) => [ + language.code, + writePage.paths( + language === finalDefaultLanguage ? '' : language.code, + 'localized.' + pageSubKey, + directory + ), + ]) + ); - await progressPromiseAll( - `Writing ${language.code}`, - queue( - [ - ...pageWrites.map((props) => () => { - const {path, page} = props; + const paths = writePage.paths( + baseDirectory, + 'localized.' + pageSubKey, + directory + ); - // TODO: This only supports one <>-style argument. - const pageSubKey = path[0]; - const directory = path[1]; + const to = writePage.to({ + baseDirectory, + pageSubKey, + paths, + }); - const localizedPaths = Object.fromEntries( - Object.entries(languages) - .filter( - ([key, language]) => key !== 'default' && !language.hidden + const absoluteTo = (targetFullKey, ...args) => { + const [groupKey, subKey] = targetFullKey.split('.'); + const from = urls.from('shared.root'); + return ( + '/' + + (groupKey === 'localized' && baseDirectory + ? from.to( + 'localizedWithBaseDirectory.' + subKey, + baseDirectory, + ...args ) - .map(([_key, language]) => [ - language.code, - writePage.paths( - language === finalDefaultLanguage ? '' : language.code, - 'localized.' + pageSubKey, - directory - ), - ]) - ); - - const paths = writePage.paths( - baseDirectory, - 'localized.' + pageSubKey, - directory - ); - - const to = writePage.to({ - baseDirectory, - pageSubKey, - paths, - }); - - const absoluteTo = (targetFullKey, ...args) => { - const [groupKey, subKey] = targetFullKey.split('.'); - const from = urls.from('shared.root'); - return ( - '/' + - (groupKey === 'localized' && baseDirectory - ? from.to( - 'localizedWithBaseDirectory.' + subKey, - baseDirectory, - ...args - ) - : from.to(targetFullKey, ...args)) - ); - }; - - // TODO: Is there some nicer way to define these, - // may8e without totally re-8inding everything for - // each page? - const bound = {}; - - bound.html = html; - - bound.link = withEntries(unbound_link, (entries) => - entries.map(([key, fn]) => [key, bindOpts(fn, {to})]) - ); - - bound.parseAttributes = bindOpts(parseAttributes, { - to, - }); - - bound.find = bindFind(wikiData, {mode: 'warn'}); - - bound.transformInline = bindOpts(transformInline, { - find: bound.find, - link: bound.link, - replacerSpec, - language, - to, - wikiData, - }); - - bound.transformMultiline = bindOpts(transformMultiline, { - transformInline: bound.transformInline, - parseAttributes: bound.parseAttributes, - }); - - bound.transformLyrics = bindOpts(transformLyrics, { - transformInline: bound.transformInline, - transformMultiline: bound.transformMultiline, - }); - - bound.iconifyURL = bindOpts(iconifyURL, { - html, - language, - to, - }); - - bound.fancifyURL = bindOpts(fancifyURL, { - html, - language, - }); - - bound.fancifyFlashURL = bindOpts(fancifyFlashURL, { - [bindOpts.bindIndex]: 2, - html, - language, - - fancifyURL: bound.fancifyURL, - }); - - bound.getRevealStringFromWarnings = bindOpts(getRevealStringFromWarnings, { - html, - language, - }); - - bound.getRevealStringFromTags = bindOpts(getRevealStringFromTags, { - language, - - getRevealStringFromWarnings: bound.getRevealStringFromWarnings, - }); - - bound.getLinkThemeString = getLinkThemeString; - - bound.getThemeString = getThemeString; - - bound.getArtistString = bindOpts(getArtistString, { - html, - link: bound.link, - language, - - iconifyURL: bound.iconifyURL, - }); - - bound.getAlbumCover = bindOpts(getAlbumCover, { - to, - }); - - bound.getTrackCover = bindOpts(getTrackCover, { - to, - }); - - bound.getFlashCover = bindOpts(getFlashCover, { - to, - }); - - bound.getArtistAvatar = bindOpts(getArtistAvatar, { - to, - }); - - bound.generateAdditionalFilesShortcut = bindOpts(generateAdditionalFilesShortcut, { - html, - language, - }); - - bound.generateAdditionalFilesList = bindOpts(generateAdditionalFilesList, { - html, - language, - }); - - bound.generateNavigationLinks = bindOpts(generateNavigationLinks, { - link: bound.link, - language, - }); - - bound.generateChronologyLinks = bindOpts(generateChronologyLinks, { - html, - language, - link: bound.link, - wikiData, - - generateNavigationLinks: bound.generateNavigationLinks, - }); - - bound.generateCoverLink = bindOpts(generateCoverLink, { - [bindOpts.bindIndex]: 0, - html, - img, - link: bound.link, - language, - to, - wikiData, - - getRevealStringFromTags: bound.getRevealStringFromTags, - }); - - bound.generateInfoGalleryLinks = bindOpts(generateInfoGalleryLinks, { - [bindOpts.bindIndex]: 2, - link: bound.link, - language, - }); - - bound.generateTrackListDividedByGroups = bindOpts(generateTrackListDividedByGroups, { - html, - language, - wikiData, - }); - - bound.getGridHTML = bindOpts(getGridHTML, { - [bindOpts.bindIndex]: 0, - img, - html, - language, - - getRevealStringFromTags: bound.getRevealStringFromTags, - }); - - bound.getAlbumGridHTML = bindOpts(getAlbumGridHTML, { - [bindOpts.bindIndex]: 0, - link: bound.link, - language, - - getAlbumCover: bound.getAlbumCover, - getGridHTML: bound.getGridHTML, - }); - - bound.getFlashGridHTML = bindOpts(getFlashGridHTML, { - [bindOpts.bindIndex]: 0, - link: bound.link, - - getFlashCover: bound.getFlashCover, - getGridHTML: bound.getGridHTML, - }); - - bound.getAlbumStylesheet = bindOpts(getAlbumStylesheet, { - to, - }); - - const pageInfo = page({ - ...bound, - - language, - - absoluteTo, - relativeTo: to, - to, - urls, - - getSizeOfAdditionalFile, - }); - - const oEmbedJSON = writePage.oEmbedJSON(pageInfo, { - language, - wikiData, - }); - - const oEmbedJSONHref = - oEmbedJSON && - wikiData.wikiInfo.canonicalBase && - wikiData.wikiInfo.canonicalBase + - urls - .from('shared.root') - .to('shared.path', paths.pathname + OEMBED_JSON_FILE); - - const pageHTML = writePage.html(pageInfo, { - defaultLanguage: finalDefaultLanguage, - language, - languages, - localizedPaths, - oEmbedJSONHref, - paths, - to, - transformMultiline: bound.transformMultiline, - wikiData, - }); - - return writePage.write({ - html: pageHTML, - oEmbedJSON, - paths, - }); - }), - ...redirectWrites.map(({fromPath, toPath, title: titleFn}) => () => { - const title = titleFn({ - language, - }); - - // TODO: This only supports one <>-style argument. - const fromPaths = writePage.paths( - baseDirectory, - 'localized.' + fromPath[0], - fromPath[1] - ); - const to = writePage.to({ - baseDirectory, - pageSubKey: fromPath[0], - paths: fromPaths, - }); - - const target = to('localized.' + toPath[0], ...toPath.slice(1)); - const html = generateRedirectPage(title, target, {language}); - return writePage.write({html, paths: fromPaths}); - }), - ], - queueSize - ) - ); + : from.to(targetFullKey, ...args)) + ); + }; + + // TODO: Is there some nicer way to define these, + // may8e without totally re-8inding everything for + // each page? + const bound = {}; + + bound.html = html; + + bound.link = withEntries(unbound_link, (entries) => + entries.map(([key, fn]) => [key, bindOpts(fn, {to})]) + ); + + bound.parseAttributes = bindOpts(parseAttributes, { + to, + }); + + bound.find = bindFind(wikiData, {mode: 'warn'}); + + bound.transformInline = bindOpts(transformInline, { + find: bound.find, + link: bound.link, + replacerSpec, + language, + to, + wikiData, + }); + + bound.transformMultiline = bindOpts(transformMultiline, { + transformInline: bound.transformInline, + parseAttributes: bound.parseAttributes, + }); + + bound.transformLyrics = bindOpts(transformLyrics, { + transformInline: bound.transformInline, + transformMultiline: bound.transformMultiline, + }); + + bound.iconifyURL = bindOpts(iconifyURL, { + html, + language, + to, + }); + + bound.fancifyURL = bindOpts(fancifyURL, { + html, + language, + }); + + bound.fancifyFlashURL = bindOpts(fancifyFlashURL, { + [bindOpts.bindIndex]: 2, + html, + language, + + fancifyURL: bound.fancifyURL, + }); + + bound.getRevealStringFromWarnings = bindOpts(getRevealStringFromWarnings, { + html, + language, + }); + + bound.getRevealStringFromTags = bindOpts(getRevealStringFromTags, { + language, + + getRevealStringFromWarnings: bound.getRevealStringFromWarnings, + }); + + bound.getLinkThemeString = getLinkThemeString; + + bound.getThemeString = getThemeString; + + bound.getArtistString = bindOpts(getArtistString, { + html, + link: bound.link, + language, + + iconifyURL: bound.iconifyURL, + }); + + bound.getAlbumCover = bindOpts(getAlbumCover, { + to, + }); + + bound.getTrackCover = bindOpts(getTrackCover, { + to, + }); + + bound.getFlashCover = bindOpts(getFlashCover, { + to, + }); + + bound.getArtistAvatar = bindOpts(getArtistAvatar, { + to, + }); + + bound.generateAdditionalFilesShortcut = bindOpts(generateAdditionalFilesShortcut, { + html, + language, + }); + + bound.generateAdditionalFilesList = bindOpts(generateAdditionalFilesList, { + html, + language, + }); + + bound.generateNavigationLinks = bindOpts(generateNavigationLinks, { + link: bound.link, + language, + }); + + bound.generateChronologyLinks = bindOpts(generateChronologyLinks, { + html, + language, + link: bound.link, + wikiData, + + generateNavigationLinks: bound.generateNavigationLinks, + }); + + bound.generateCoverLink = bindOpts(generateCoverLink, { + [bindOpts.bindIndex]: 0, + html, + img, + link: bound.link, + language, + to, + wikiData, + + getRevealStringFromTags: bound.getRevealStringFromTags, + }); + + bound.generateInfoGalleryLinks = bindOpts(generateInfoGalleryLinks, { + [bindOpts.bindIndex]: 2, + link: bound.link, + language, + }); + + bound.generateTrackListDividedByGroups = bindOpts(generateTrackListDividedByGroups, { + html, + language, + wikiData, + }); + + bound.getGridHTML = bindOpts(getGridHTML, { + [bindOpts.bindIndex]: 0, + img, + html, + language, + + getRevealStringFromTags: bound.getRevealStringFromTags, + }); + + bound.getAlbumGridHTML = bindOpts(getAlbumGridHTML, { + [bindOpts.bindIndex]: 0, + link: bound.link, + language, + + getAlbumCover: bound.getAlbumCover, + getGridHTML: bound.getGridHTML, + }); + + bound.getFlashGridHTML = bindOpts(getFlashGridHTML, { + [bindOpts.bindIndex]: 0, + link: bound.link, + + getFlashCover: bound.getFlashCover, + getGridHTML: bound.getGridHTML, + }); + + bound.getAlbumStylesheet = bindOpts(getAlbumStylesheet, { + to, + }); + + const pageInfo = page({ + ...bound, + + language, + + absoluteTo, + relativeTo: to, + to, + urls, + + getSizeOfAdditionalFile, + }); + + const oEmbedJSON = writePage.oEmbedJSON(pageInfo, { + language, + wikiData, + }); + + const oEmbedJSONHref = + oEmbedJSON && + wikiData.wikiInfo.canonicalBase && + wikiData.wikiInfo.canonicalBase + + urls + .from('shared.root') + .to('shared.path', paths.pathname + OEMBED_JSON_FILE); + + const pageHTML = writePage.html(pageInfo, { + defaultLanguage: finalDefaultLanguage, + language, + languages, + localizedPaths, + oEmbedJSONHref, + paths, + to, + transformMultiline: bound.transformMultiline, + wikiData, + }); + + return writePage.write({ + html: pageHTML, + oEmbedJSON, + paths, + }); + }), + ...redirectWrites.map(({fromPath, toPath, title: titleFn}) => () => { + const title = titleFn({ + language, + }); + + // TODO: This only supports one <>-style argument. + const fromPaths = writePage.paths( + baseDirectory, + 'localized.' + fromPath[0], + fromPath[1] + ); + const to = writePage.to({ + baseDirectory, + pageSubKey: fromPath[0], + paths: fromPaths, + }); + + const target = to('localized.' + toPath[0], ...toPath.slice(1)); + const html = generateRedirectPage(title, target, {language}); + return writePage.write({html, paths: fromPaths}); + }), + ], queueSize)); }; await wrapLanguages(perLanguageFn, { diff --git a/src/url-spec.js b/src/url-spec.js index bab97efa..ce479267 100644 --- a/src/url-spec.js +++ b/src/url-spec.js @@ -1,5 +1,3 @@ -/** @format */ - import {withEntries} from './util/sugar.js'; const urlSpec = { @@ -87,8 +85,7 @@ const urlSpec = { // so it should never be referenced manually. urlSpec.localizedWithBaseDirectory = { paths: withEntries(urlSpec.localized.paths, (entries) => - entries.map(([key, path]) => [key, '<>/' + path]) - ), + entries.map(([key, path]) => [key, '<>/' + path])), }; export default urlSpec; diff --git a/src/util/cli.js b/src/util/cli.js index 99c0638c..f1a31900 100644 --- a/src/util/cli.js +++ b/src/util/cli.js @@ -1,5 +1,3 @@ -/** @format */ - // Utility functions for CLI- and de8ugging-rel8ted stuff. // // A 8unch of these depend on process.stdout 8eing availa8le, so they won't diff --git a/src/util/colors.js b/src/util/colors.js index 5848a820..a0cc7486 100644 --- a/src/util/colors.js +++ b/src/util/colors.js @@ -1,16 +1,25 @@ -/** @format */ - // Color and theming utility functions! Handy. // Graciously stolen from https://stackoverflow.com/a/54071699! ::::) // in: r,g,b in [0,1], out: h in [0,360) and s,l in [0,1] export function rgb2hsl(r, g, b) { let a = Math.max(r, g, b), - n = a - Math.min(r, g, b), - f = 1 - Math.abs(a + a - n - 1); + n = a - Math.min(r, g, b), + f = 1 - Math.abs(a + a - n - 1); + let h = - n && (a == r ? (g - b) / n : a == g ? 2 + (b - r) / n : 4 + (r - g) / n); - return [60 * (h < 0 ? h + 6 : h), f ? n / f : 0, (a + a - n) / 2]; + n && + a == r + ? (g - b) / n + : a == g + ? 2 + (b - r) / n + : 4 + (r - g) / n; + + return [ + 60 * (h < 0 ? h + 6 : h), + f ? n / f : 0, + (a + a - n) / 2 + ]; } export function getColors(primary) { @@ -19,10 +28,10 @@ export function getColors(primary) { .match(/[0-9a-fA-F]{2,2}/g) .slice(0, 3) .map((val) => parseInt(val, 16) / 255); + const [h, s, l] = rgb2hsl(r, g, b); - const dim = `hsl(${Math.round(h)}deg, ${Math.round(s * 50)}%, ${Math.round( - l * 80 - )}%)`; + + const dim = `hsl(${Math.round(h)}deg, ${Math.round(s * 50)}%, ${Math.round(l * 80)}%)`; const bg = `hsla(${Math.round(h)}deg, ${Math.round(s * 15)}%, 12%, 0.80)`; return { diff --git a/src/util/find.js b/src/util/find.js index 71026fa2..ed0a6809 100644 --- a/src/util/find.js +++ b/src/util/find.js @@ -1,5 +1,3 @@ -/** @format */ - import {color, logWarn} from './cli.js'; import {inspect} from 'util'; @@ -26,9 +24,7 @@ function findHelper(keys, findFns = {}) { const byDirectory = findFns.byDirectory || matchDirectory; const byName = findFns.byName || matchName; - const keyRefRegex = new RegExp( - String.raw`^(?:(${keys.join('|')}):(?=\S))?(.*)$` - ); + const keyRefRegex = new RegExp(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 @@ -37,9 +33,7 @@ function findHelper(keys, findFns = {}) { return (fullRef, data, {mode = 'warn'} = {}) => { if (!fullRef) return null; if (typeof fullRef !== 'string') { - throw new Error( - `Got a reference that is ${typeof fullRef}, not string: ${fullRef}` - ); + throw new Error(`Got a reference that is ${typeof fullRef}, not string: ${fullRef}`); } if (!data) { diff --git a/src/util/html.js b/src/util/html.js index 752291e9..0a586223 100644 --- a/src/util/html.js +++ b/src/util/html.js @@ -1,5 +1,3 @@ -/** @format */ - // Some really simple functions for formatting HTML content. // COMPREHENSIVE! @@ -116,16 +114,18 @@ export function escapeAttributeValue(value) { 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]; else - throw new Error( - `Attribute value for ${key} should be primitive or array, got ${typeof val}` - ); + throw new Error(`Attribute value for ${key} should be primitive or array, got ${typeof val}`); }) .filter(([_key, _val, keep]) => keep) .map(([key, val]) => diff --git a/src/util/io.js b/src/util/io.js index cfd6708d..6cc89b56 100644 --- a/src/util/io.js +++ b/src/util/io.js @@ -1,5 +1,3 @@ -/** @format */ - // Utility functions for interacting with files and other external data // interfacey constructs. diff --git a/src/util/link.js b/src/util/link.js index 8fe3c2f4..9de4c95a 100644 --- a/src/util/link.js +++ b/src/util/link.js @@ -1,5 +1,3 @@ -/** @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") @@ -35,18 +33,18 @@ export function getLinkThemeString(color) { const appendIndexHTMLRegex = /^(?!https?:\/\/).+\/$/; const linkHelper = - (hrefFn, {color = true, attr = null} = {}) => - ( - thing, - { - to, - text = '', - attributes = null, - class: className = '', - color: color2 = true, - hash = '', - } - ) => { + (hrefFn, { + color = true, + attr = null, + } = {}) => + (thing, { + to, + text = '', + attributes = null, + class: className = '', + color: color2 = true, + hash = '', + }) => { let href = hrefFn(thing, {to}); if (link.globalOptions.appendIndexHTML) { @@ -88,6 +86,7 @@ const linkDirectory = (key, {expose = null, attr = null, ...conf} = {}) => const linkPathname = (key, conf) => linkHelper(({directory: pathname}, {to}) => to(key, pathname), conf); + const linkIndex = (key, conf) => linkHelper((_, {to}) => to('localized.' + key), conf); @@ -143,8 +142,7 @@ const link = { to( 'media.albumAdditionalFile', fakeFileObject.album.directory, - fakeFileObject.name - ), + fakeFileObject.name), {color: false} ), albumAdditionalFile: ({file, album}, {to}) => @@ -153,8 +151,7 @@ const link = { name: file, album, }, - {to} - ), + {to}), media: linkPathname('media.path', {color: false}), root: linkPathname('shared.path', {color: false}), diff --git a/src/util/magic-constants.js b/src/util/magic-constants.js index dbdbcfda..73fdbc6d 100644 --- a/src/util/magic-constants.js +++ b/src/util/magic-constants.js @@ -1,5 +1,3 @@ -/** @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 diff --git a/src/util/node-utils.js b/src/util/node-utils.js index df446654..252e920a 100644 --- a/src/util/node-utils.js +++ b/src/util/node-utils.js @@ -1,5 +1,3 @@ -/** @format */ - // Utility functions which are only relevant to particular Node.js constructs. import {fileURLToPath} from 'url'; diff --git a/src/util/replacer.js b/src/util/replacer.js index ea5a674d..9d602ca9 100644 --- a/src/util/replacer.js +++ b/src/util/replacer.js @@ -1,15 +1,10 @@ -/** @format */ - import {logError, logWarn} from './cli.js'; import {escapeRegex} from './sugar.js'; export function validateReplacerSpec(replacerSpec, {find, link}) { let success = true; - for (const [ - key, - {link: linkKey, find: findKey, html}, - ] of Object.entries(replacerSpec)) { + for (const [key, {link: linkKey, find: findKey, 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.`; success = false; @@ -436,14 +431,18 @@ function transformNodes(nodes, opts) { return nodes.map((node) => transformNode(node, opts)).join(''); } -export function transformInline( - input, - {replacerSpec, find, link, language, to, wikiData} -) { +export function transformInline(input, { + replacerSpec, + find, + language, + link, + 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 (!link) throw new Error('Expected link'); if (!to) throw new Error('Expected to'); if (!wikiData) throw new Error('Expected wikiData'); diff --git a/src/util/serialize.js b/src/util/serialize.js index 9aa8b0c5..73a31374 100644 --- a/src/util/serialize.js +++ b/src/util/serialize.js @@ -1,5 +1,3 @@ -/** @format */ - export function serializeLink(thing) { const ret = {}; ret.name = thing.name; @@ -25,11 +23,10 @@ export function serializeImagePaths(original, {thumb}) { }; } -export function serializeCover( - thing, - pathFunction, - {serializeImagePaths, urls} -) { +export function serializeCover(thing, pathFunction, { + serializeImagePaths, + urls, +}) { const coverPath = pathFunction(thing, { to: urls.from('media.root').to, }); diff --git a/src/util/sugar.js b/src/util/sugar.js index 24ae8639..808a7e1c 100644 --- a/src/util/sugar.js +++ b/src/util/sugar.js @@ -1,5 +1,3 @@ -/** @format */ - // Syntactic sugar! (Mostly.) // Generic functions - these are useful just a8out everywhere. // @@ -17,9 +15,7 @@ import {color} from './cli.js'; export function* splitArray(array, fn) { let lastIndex = 0; while (lastIndex < array.length) { - let nextIndex = array.findIndex( - (item, index) => index >= lastIndex && fn(item) - ); + let nextIndex = array.findIndex((item, index) => index >= lastIndex && fn(item)); if (nextIndex === -1) { nextIndex = array.length; } @@ -54,8 +50,7 @@ export function accumulateSum(array, fn = x => x) { (accumulator, value, index, array) => accumulator + fn(value, index, array) ?? 0, - 0 - ); + 0); } export const mapInPlace = (array, fn) => @@ -275,11 +270,10 @@ export function mapAggregate(array, fn, aggregateOpts) { return _mapAggregate('sync', null, array, fn, aggregateOpts); } -export function mapAggregateAsync( - array, - fn, - {promiseAll = Promise.all.bind(Promise), ...aggregateOpts} = {} -) { +export function mapAggregateAsync(array, fn, { + promiseAll = Promise.all.bind(Promise), + ...aggregateOpts +} = {}) { return _mapAggregate('async', promiseAll, array, fn, aggregateOpts); } @@ -299,10 +293,11 @@ export function _mapAggregate(mode, promiseAll, array, fn, aggregateOpts) { .filter((value) => value !== failureSymbol); return {result, aggregate}; } else { - return promiseAll(array.map(aggregate.wrapAsync(fn))).then((values) => { - const result = values.filter((value) => value !== failureSymbol); - return {result, aggregate}; - }); + return promiseAll(array.map(aggregate.wrapAsync(fn))) + .then((values) => { + const result = values.filter((value) => value !== failureSymbol); + return {result, aggregate}; + }); } } @@ -317,11 +312,10 @@ export function filterAggregate(array, fn, aggregateOpts) { return _filterAggregate('sync', null, array, fn, aggregateOpts); } -export async function filterAggregateAsync( - array, - fn, - {promiseAll = Promise.all.bind(Promise), ...aggregateOpts} = {} -) { +export async function filterAggregateAsync(array, fn, { + promiseAll = Promise.all.bind(Promise), + ...aggregateOpts +} = {}) { return _filterAggregate('async', promiseAll, array, fn, aggregateOpts); } @@ -357,24 +351,20 @@ function _filterAggregate(mode, promiseAll, array, fn, aggregateOpts) { if (mode === 'sync') { const result = array - .map( - aggregate.wrap((input, index, array) => { - const output = fn(input, index, array); - return {input, output}; - }) - ) + .map(aggregate.wrap((input, index, array) => { + const output = fn(input, index, array); + return {input, output}; + })) .filter(filterFunction) .map(mapFunction); return {result, aggregate}; } else { return promiseAll( - array.map( - aggregate.wrapAsync(async (input, index, array) => { - const output = await fn(input, index, array); - return {input, output}; - }) - ) + array.map(aggregate.wrapAsync(async (input, index, array) => { + const output = await fn(input, index, array); + return {input, output}; + })) ).then((values) => { const result = values.filter(filterFunction).map(mapFunction); @@ -414,10 +404,10 @@ export function _withAggregate(mode, aggregateOpts, fn) { } } -export function showAggregate( - topError, - {pathToFile = (p) => p, showTraces = true} = {} -) { +export function showAggregate(topError, { + pathToFile = (p) => p, + showTraces = true, +} = {}) { const recursive = (error, {level}) => { let header = showTraces ? `[${error.constructor.name || 'unnamed'}] ${ diff --git a/src/util/urls.js b/src/util/urls.js index d86c047d..1f9cd9c0 100644 --- a/src/util/urls.js +++ b/src/util/urls.js @@ -1,5 +1,3 @@ -/** @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 @@ -28,9 +26,7 @@ export function generateURLs(urlSpec) { const group = obj[groupKey]; if (!Object.hasOwn(group, subKey)) { - throw new Error( - `Expected valid subkey (got ${subKey} for group ${groupKey})` - ); + throw new Error(`Expected valid subkey (got ${subKey} for group ${groupKey})`); } return { @@ -47,9 +43,8 @@ export function generateURLs(urlSpec) { 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); @@ -117,14 +112,14 @@ export function generateURLs(urlSpec) { }; const generateFrom = () => { - const map = withEntries(urlSpec, (entries) => - entries.map(([key, group]) => [ + const map = withEntries( + urlSpec, + (entries) => entries.map(([key, group]) => [ key, withEntries(group.paths, (entries) => entries.map(([key, path]) => [key, generateTo(path, group)]) ), - ]) - ); + ])); const from = (key) => getValueForFullKey(map, key).value; diff --git a/src/util/wiki-data.js b/src/util/wiki-data.js index b0b0b2e0..7d2cfa9f 100644 --- a/src/util/wiki-data.js +++ b/src/util/wiki-data.js @@ -1,5 +1,3 @@ -/** @format */ - // Utility functions for interacting with wiki data. import {empty} from './sugar.js'; @@ -144,10 +142,9 @@ export function normalizeName(s) { // ...trackData]), because the initial sort places albums before tracks - and // sortByDirectory will handle the rest, given all directories are unique // except when album and track directories overlap with each other. -export function sortByDirectory( - data, - {getDirectory = (o) => o.directory} = {} -) { +export function sortByDirectory(data, { + getDirectory = (o) => o.directory, +} = {}) { return data.sort((a, b) => { const ad = getDirectory(a); const bd = getDirectory(b); @@ -155,7 +152,9 @@ export function sortByDirectory( }); } -export function sortByName(data, {getName = (o) => o.name} = {}) { +export function sortByName(data, { + getName = (o) => o.name, +} = {}) { const nameMap = new Map(); const normalizedNameMap = new Map(); for (const o of data) { @@ -178,7 +177,9 @@ 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); @@ -269,7 +270,10 @@ export function sortByConditions(data, conditions) { // Expects thing properties: // * directory (or override getDirectory) // * name (or override getName) -export function sortAlphabetically(data, {getDirectory, getName} = {}) { +export function sortAlphabetically(data, { + getDirectory, + getName, +} = {}) { sortByDirectory(data, {getDirectory}); sortByName(data, {getName}); return data; @@ -279,10 +283,11 @@ export function sortAlphabetically(data, {getDirectory, getName} = {}) { // * directory (or override getDirectory) // * name (or override getName) // * date (or override getDate) -export function sortChronologically( - data, - {getDirectory, getName, getDate} = {} -) { +export function sortChronologically(data, { + getDirectory, + getName, + getDate, +} = {}) { sortAlphabetically(data, {getDirectory, getName}); sortByDate(data, {getDate}); return data; @@ -296,7 +301,9 @@ 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]); @@ -320,9 +327,8 @@ export function sortAlbumsTracksChronologically(data, {getDate} = {}) { // Specific data utilities export function filterAlbumsByCommentary(albums) { - return albums.filter((album) => - [album, ...album.tracks].some((x) => x.commentary) - ); + return albums + .filter((album) => [album, ...album.tracks].some((x) => x.commentary)); } export function getAlbumCover(album, {to}) { @@ -387,12 +393,7 @@ export function getTrackCover(track, {to}) { if (!track.hasCoverArt) { return getAlbumCover(track.album, {to}); } else { - return to( - 'media.trackCover', - track.album.directory, - track.directory, - track.coverArtFileExtension - ); + return to('media.trackCover', track.album.directory, track.directory, track.coverArtFileExtension); } } @@ -455,11 +456,7 @@ export function getNewAdditions(numAlbums, {wikiData}) { const currentDate = sortedAlbums[i].dateAddedToWiki; const groupMap = new Map(); const groupArray = []; - for ( - let album; - (album = sortedAlbums[i]) && +album.dateAddedToWiki === +currentDate; - i++ - ) { + for (let album; (album = sortedAlbums[i]) && +album.dateAddedToWiki === +currentDate; i++) { const primaryGroup = album.groups[0]; if (groupMap.has(primaryGroup)) { groupMap.get(primaryGroup).push(album); @@ -510,6 +507,7 @@ export function getNewReleases(numReleases, {wikiData}) { const latestFirst = albumData .filter((album) => album.isListedOnHomepage) .reverse(); + const majorReleases = latestFirst.filter((album) => album.isMajorRelease); majorReleases.splice(1); |