From 218a99a3164e8ae6967335190b72fd36275d1892 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 21 Aug 2023 10:58:55 -0300 Subject: data, test: track: inherit album props more declaratively --- src/data/yaml.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 35943199..13412f17 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -316,6 +316,10 @@ export const processTrackDocument = makeProcessDocument(T.Track, { 'Date First Released': (value) => new Date(value), 'Cover Art Date': (value) => new Date(value), + 'Has Cover Art': (value) => + (value === true ? false : + value === false ? true : + value), 'Artists': parseContributors, 'Contributors': parseContributors, @@ -336,7 +340,7 @@ export const processTrackDocument = makeProcessDocument(T.Track, { dateFirstReleased: 'Date First Released', coverArtDate: 'Cover Art Date', coverArtFileExtension: 'Cover Art File Extension', - hasCoverArt: 'Has Cover Art', + disableCoverArt: 'Has Cover Art', // This gets transformed to flip true/false. lyrics: 'Lyrics', commentary: 'Commentary', -- cgit 1.3.0-6-gf8a5 From d4af649bfdd546bd87b1a440bdba8152d010937e Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 21 Aug 2023 21:17:38 -0300 Subject: yaml: fix disableCoverArt -> disableUniqueCoverArt --- src/data/yaml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 13412f17..25eda3c5 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -340,7 +340,7 @@ export const processTrackDocument = makeProcessDocument(T.Track, { dateFirstReleased: 'Date First Released', coverArtDate: 'Cover Art Date', coverArtFileExtension: 'Cover Art File Extension', - disableCoverArt: 'Has Cover Art', // This gets transformed to flip true/false. + disableUniqueCoverArt: 'Has Cover Art', // This gets transformed to flip true/false. lyrics: 'Lyrics', commentary: 'Commentary', -- cgit 1.3.0-6-gf8a5 From f562896d4d67558a32726f7086beebf29019a44d Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Fri, 25 Aug 2023 14:06:00 -0300 Subject: yaml, test: mutate/decache wikiData in more reusable ways --- src/data/yaml.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 25eda3c5..2ad2d41d 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -1320,13 +1320,27 @@ export async function loadAndProcessDataDocuments({dataPath}) { // Data linking! Basically, provide (portions of) wikiData to the Things which // require it - they'll expose dynamically computed properties as a result (many -// of which are required for page HTML generation). -export function linkWikiDataArrays(wikiData) { +// of which are required for page HTML generation and other expected behavior). +// +// The XXX_decacheWikiData option should be used specifically to mark +// points where you *aren't* replacing any of the arrays under wikiData with +// new values, and are using linkWikiDataArrays to instead "decache" data +// properties which depend on any of them. It's currently not possible for +// a CacheableObject to depend directly on the value of a property exposed +// on some other CacheableObject, so when those values change, you have to +// manually decache before the object will realize its cache isn't valid +// anymore. +export function linkWikiDataArrays(wikiData, { + XXX_decacheWikiData = false, +} = {}) { function assignWikiData(things, ...keys) { + if (things === undefined) return; for (let i = 0; i < things.length; i++) { const thing = things[i]; for (let j = 0; j < keys.length; j++) { const key = keys[j]; + if (!(key in wikiData)) continue; + if (XXX_decacheWikiData) thing[key] = []; thing[key] = wikiData[key]; } } @@ -1344,7 +1358,7 @@ export function linkWikiDataArrays(wikiData) { assignWikiData(WD.flashData, 'artistData', 'flashActData', 'trackData'); assignWikiData(WD.flashActData, 'flashData'); assignWikiData(WD.artTagData, 'albumData', 'trackData'); - assignWikiData(WD.homepageLayout.rows, 'albumData', 'groupData'); + assignWikiData(WD.homepageLayout?.rows, 'albumData', 'groupData'); } export function sortWikiDataArrays(wikiData) { -- cgit 1.3.0-6-gf8a5 From eb00f2993a1aaaba171ad6c918656552f80bb748 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 7 Sep 2023 12:38:34 -0300 Subject: data: import Thing.common utilities directly Also rename 'color' (from #cli) to 'colors'. --- src/data/yaml.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 2ad2d41d..c0aad943 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -7,7 +7,7 @@ import {inspect as nodeInspect} from 'node:util'; import yaml from 'js-yaml'; -import {color, ENABLE_COLOR, logInfo, logWarn} from '#cli'; +import {colors, ENABLE_COLOR, logInfo, logWarn} from '#cli'; import find, {bindFind} from '#find'; import {traverse} from '#node-utils'; import T from '#things'; @@ -137,7 +137,7 @@ function makeProcessDocument( const name = document[nameField]; error.message = name ? `(name: ${inspect(name)}) ${error.message}` - : `(${color.dim(`no name found`)}) ${error.message}`; + : `(${colors.dim(`no name found`)}) ${error.message}`; throw error; } }; @@ -195,7 +195,7 @@ function makeProcessDocument( const thing = Reflect.construct(thingClass, []); - withAggregate({message: `Errors applying ${color.green(thingClass.name)} properties`}, ({call}) => { + withAggregate({message: `Errors applying ${colors.green(thingClass.name)} properties`}, ({call}) => { for (const [property, value] of Object.entries(sourceProperties)) { call(() => (thing[property] = value)); } @@ -228,7 +228,7 @@ makeProcessDocument.FieldCombinationsError = class FieldCombinationsError extend makeProcessDocument.FieldCombinationError = class FieldCombinationError extends Error { constructor(fields, message) { const fieldNames = Object.keys(fields); - const combinePart = `Don't combine ${fieldNames.map(field => color.red(field)).join(', ')}`; + const combinePart = `Don't combine ${fieldNames.map(field => colors.red(field)).join(', ')}`; const messagePart = (typeof message === 'function' @@ -1009,7 +1009,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: ${colors.bright(colors.blue(path.relative(dataPath, x.file)))})`; throw error; } }; @@ -1032,7 +1032,7 @@ export async function loadAndProcessDataDocuments({dataPath}) { // just without the callbacks. Thank you. const filterBlankDocuments = documents => { const aggregate = openAggregate({ - message: `Found blank documents - check for extra '${color.cyan(`---`)}'`, + message: `Found blank documents - check for extra '${colors.cyan(`---`)}'`, }); const filteredDocuments = @@ -1076,10 +1076,10 @@ export async function loadAndProcessDataDocuments({dataPath}) { if (count === 1) { const range = `#${start + 1}`; - parts.push(`${count} document (${color.yellow(range)}), `); + parts.push(`${count} document (${colors.yellow(range)}), `); } else { const range = `#${start + 1}-${end + 1}`; - parts.push(`${count} documents (${color.yellow(range)}), `); + parts.push(`${count} documents (${colors.yellow(range)}), `); } if (previous === null) { @@ -1089,7 +1089,7 @@ export async function loadAndProcessDataDocuments({dataPath}) { } else { const previousDescription = Object.entries(previous).at(0).join(': '); const nextDescription = Object.entries(next).at(0).join(': '); - parts.push(`between "${color.cyan(previousDescription)}" and "${color.cyan(nextDescription)}"`); + parts.push(`between "${colors.cyan(previousDescription)}" and "${colors.cyan(nextDescription)}"`); } aggregate.push(new Error(parts.join(''))); @@ -1395,7 +1395,7 @@ 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}) => { + aggregate.nest({message: `Duplicate directories found in ${colors.green('wikiData.' + thingDataProp)}`}, ({call}) => { const directoryPlaces = Object.create(null); const duplicateDirectories = []; @@ -1421,7 +1421,7 @@ export function filterDuplicateDirectories(wikiData) { const places = directoryPlaces[directory]; call(() => { throw new Error( - `Duplicate directory ${color.green(directory)}:\n` + + `Duplicate directory ${colors.green(directory)}:\n` + places.map((thing) => ` - ` + inspect(thing)).join('\n') ); }); @@ -1516,7 +1516,7 @@ export function filterReferenceErrors(wikiData) { for (const [thingDataProp, providedProcessDocumentFn, propSpec] of referenceSpec) { const thingData = getNestedProp(wikiData, thingDataProp); - aggregate.nest({message: `Reference errors in ${color.green('wikiData.' + thingDataProp)}`}, ({nest}) => { + aggregate.nest({message: `Reference errors in ${colors.green('wikiData.' + thingDataProp)}`}, ({nest}) => { const things = Array.isArray(thingData) ? thingData : [thingData]; for (const thing of things) { @@ -1535,7 +1535,7 @@ export function filterReferenceErrors(wikiData) { const value = thing[property]; if (value === undefined) { - push(new TypeError(`Property ${color.red(property)} isn't valid for ${color.green(thing.constructor.name)}`)); + push(new TypeError(`Property ${colors.red(property)} isn't valid for ${colors.green(thing.constructor.name)}`)); continue; } @@ -1553,7 +1553,7 @@ export function filterReferenceErrors(wikiData) { // No need to check if the original exists here. Aliases are automatically // created from a field on the original, so the original certainly exists. const original = find.artist(alias.aliasedArtistRef, wikiData.artistData, {mode: 'quiet'}); - throw new Error(`Reference ${color.red(contribRef.who)} is to an alias, should be ${color.green(original.name)}`); + throw new Error(`Reference ${colors.red(contribRef.who)} is to an alias, should be ${colors.green(original.name)}`); } return boundFind.artist(contribRef.who); @@ -1578,12 +1578,12 @@ export function filterReferenceErrors(wikiData) { const shouldBeMessage = (originalByName - ? color.green(original.name) + ? colors.green(original.name) : original - ? color.green('track:' + original.directory) - : color.green(track.originalReleaseTrackByRef)); + ? colors.green('track:' + original.directory) + : colors.green(track.originalReleaseTrackByRef)); - throw new Error(`Reference ${color.red(trackRef)} is to a rerelease, should be ${shouldBeMessage}`); + throw new Error(`Reference ${colors.red(trackRef)} is to a rerelease, should be ${shouldBeMessage}`); } return track; @@ -1614,13 +1614,13 @@ export function filterReferenceErrors(wikiData) { const fieldPropertyMessage = (processDocumentFn?.propertyFieldMapping?.[property] - ? ` in field ${color.green(processDocumentFn.propertyFieldMapping[property])}` - : ` in property ${color.green(property)}`); + ? ` in field ${colors.green(processDocumentFn.propertyFieldMapping[property])}` + : ` in property ${colors.green(property)}`); const findFnMessage = (findFnKey.startsWith('_') ? `` - : ` (${color.green('find.' + findFnKey)})`); + : ` (${colors.green('find.' + findFnKey)})`); const errorMessage = (Array.isArray(value) -- cgit 1.3.0-6-gf8a5 From a24a72339f6e6e416a797d869fe9c4d9057fcac0 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 7 Sep 2023 17:23:54 -0300 Subject: data: custom _homepageSourceGroup reference validation function --- src/data/yaml.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index c0aad943..8aca3299 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -1490,7 +1490,7 @@ export function filterReferenceErrors(wikiData) { }], ['homepageLayout.rows', undefined, { - sourceGroupByRef: 'group', + sourceGroupByRef: '_homepageSourceGroup', sourceAlbumsByRef: 'album', }], @@ -1560,6 +1560,16 @@ export function filterReferenceErrors(wikiData) { }; break; + case '_homepageSourceGroup': + findFn = groupRef => { + if (groupRef === 'new-additions' || groupRef === 'new-releases') { + return true; + } + + return boundFind.group(groupRef); + }; + break; + case '_trackNotRerelease': findFn = trackRef => { const track = find.track(trackRef, wikiData.trackData, {mode: 'error'}); -- cgit 1.3.0-6-gf8a5 From bbccaf51222cb4bed73466164496f5bc1030292c Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Thu, 7 Sep 2023 17:30:54 -0300 Subject: data: roll paired "byRef" and "dynamic" properties into one --- src/data/yaml.js | 133 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 66 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 8aca3299..e1e5803d 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -10,7 +10,7 @@ import yaml from 'js-yaml'; import {colors, ENABLE_COLOR, logInfo, logWarn} from '#cli'; import find, {bindFind} from '#find'; import {traverse} from '#node-utils'; -import T from '#things'; +import T, {CacheableObject, Thing} from '#things'; import { conditionallySuppressError, @@ -278,11 +278,11 @@ export const processAlbumDocument = makeProcessDocument(T.Album, { coverArtFileExtension: 'Cover Art File Extension', trackCoverArtFileExtension: 'Track Art File Extension', - wallpaperArtistContribsByRef: 'Wallpaper Artists', + wallpaperArtistContribs: 'Wallpaper Artists', wallpaperStyle: 'Wallpaper Style', wallpaperFileExtension: 'Wallpaper File Extension', - bannerArtistContribsByRef: 'Banner Artists', + bannerArtistContribs: 'Banner Artists', bannerStyle: 'Banner Style', bannerFileExtension: 'Banner File Extension', bannerDimensions: 'Banner Dimensions', @@ -290,11 +290,11 @@ export const processAlbumDocument = makeProcessDocument(T.Album, { commentary: 'Commentary', additionalFiles: 'Additional Files', - artistContribsByRef: 'Artists', - coverArtistContribsByRef: 'Cover Artists', - trackCoverArtistContribsByRef: 'Default Track Cover Artists', - groupsByRef: 'Groups', - artTagsByRef: 'Art Tags', + artistContribs: 'Artists', + coverArtistContribs: 'Cover Artists', + trackCoverArtistContribs: 'Default Track Cover Artists', + groups: 'Groups', + artTags: 'Art Tags', }, }); @@ -348,13 +348,13 @@ export const processTrackDocument = makeProcessDocument(T.Track, { sheetMusicFiles: 'Sheet Music Files', midiProjectFiles: 'MIDI Project Files', - originalReleaseTrackByRef: 'Originally Released As', - referencedTracksByRef: 'Referenced Tracks', - sampledTracksByRef: 'Sampled Tracks', - artistContribsByRef: 'Artists', - contributorContribsByRef: 'Contributors', - coverArtistContribsByRef: 'Cover Artists', - artTagsByRef: 'Art Tags', + originalReleaseTrack: 'Originally Released As', + referencedTracks: 'Referenced Tracks', + sampledTracks: 'Sampled Tracks', + artistContribs: 'Artists', + contributorContribs: 'Contributors', + coverArtistContribs: 'Cover Artists', + artTags: 'Art Tags', }, invalidFieldCombinations: [ @@ -424,8 +424,8 @@ export const processFlashDocument = makeProcessDocument(T.Flash, { date: 'Date', coverArtFileExtension: 'Cover Art File Extension', - featuredTracksByRef: 'Featured Tracks', - contributorContribsByRef: 'Contributors', + featuredTracks: 'Featured Tracks', + contributorContribs: 'Contributors', }, }); @@ -470,7 +470,7 @@ export const processGroupDocument = makeProcessDocument(T.Group, { description: 'Description', urls: 'URLs', - featuredAlbumsByRef: 'Featured Albums', + featuredAlbums: 'Featured Albums', }, }); @@ -501,7 +501,7 @@ export const processWikiInfoDocument = makeProcessDocument(T.WikiInfo, { footerContent: 'Footer Content', defaultLanguage: 'Default Language', canonicalBase: 'Canonical Base', - divideTrackListsByGroupsByRef: 'Divide Track Lists By Groups', + divideTrackListsByGroups: 'Divide Track Lists By Groups', enableFlashesAndGames: 'Enable Flashes & Games', enableListings: 'Enable Listings', enableNews: 'Enable News', @@ -536,9 +536,9 @@ export const homepageLayoutRowTypeProcessMapping = { albums: makeProcessHomepageLayoutRowDocument(T.HomepageLayoutAlbumsRow, { propertyFieldMapping: { displayStyle: 'Display Style', - sourceGroupByRef: 'Group', + sourceGroup: 'Group', countAlbumsFromGroup: 'Count', - sourceAlbumsByRef: 'Albums', + sourceAlbums: 'Albums', actionLinks: 'Actions', }, }), @@ -771,13 +771,13 @@ export const dataSteps = [ let currentTrackSection = { name: `Default Track Section`, isDefaultTrackSection: true, - tracksByRef: [], + tracks: [], }; - const albumRef = T.Thing.getReference(album); + const albumRef = Thing.getReference(album); const closeCurrentTrackSection = () => { - if (!empty(currentTrackSection.tracksByRef)) { + if (!empty(currentTrackSection.tracks)) { trackSections.push(currentTrackSection); } }; @@ -791,7 +791,7 @@ export const dataSteps = [ color: entry.color, dateOriginallyReleased: entry.dateOriginallyReleased, isDefaultTrackSection: false, - tracksByRef: [], + tracks: [], }; continue; @@ -799,9 +799,9 @@ export const dataSteps = [ trackData.push(entry); - entry.dataSourceAlbumByRef = albumRef; + entry.dataSourceAlbum = albumRef; - currentTrackSection.tracksByRef.push(T.Thing.getReference(entry)); + currentTrackSection.tracks.push(Thing.getReference(entry)); } closeCurrentTrackSection(); @@ -825,12 +825,12 @@ export const dataSteps = [ const artistData = results; const artistAliasData = results.flatMap((artist) => { - const origRef = T.Thing.getReference(artist); + const origRef = Thing.getReference(artist); return artist.aliasNames?.map((name) => { const alias = new T.Artist(); alias.name = name; alias.isAlias = true; - alias.aliasedArtistRef = origRef; + alias.aliasedArtist = origRef; alias.artistData = artistData; return alias; }) ?? []; @@ -854,7 +854,7 @@ export const dataSteps = [ save(results) { let flashAct; - let flashesByRef = []; + let flashRefs = []; if (results[0] && !(results[0] instanceof T.FlashAct)) { throw new Error(`Expected an act at top of flash data file`); @@ -863,18 +863,18 @@ export const dataSteps = [ for (const thing of results) { if (thing instanceof T.FlashAct) { if (flashAct) { - Object.assign(flashAct, {flashesByRef}); + Object.assign(flashAct, {flashes: flashRefs}); } flashAct = thing; - flashesByRef = []; + flashRefs = []; } else { - flashesByRef.push(T.Thing.getReference(thing)); + flashRefs.push(Thing.getReference(thing)); } } if (flashAct) { - Object.assign(flashAct, {flashesByRef}); + Object.assign(flashAct, {flashes: flashRefs}); } const flashData = results.filter((x) => x instanceof T.Flash); @@ -897,7 +897,7 @@ export const dataSteps = [ save(results) { let groupCategory; - let groupsByRef = []; + let groupRefs = []; if (results[0] && !(results[0] instanceof T.GroupCategory)) { throw new Error(`Expected a category at top of group data file`); @@ -906,18 +906,18 @@ export const dataSteps = [ for (const thing of results) { if (thing instanceof T.GroupCategory) { if (groupCategory) { - Object.assign(groupCategory, {groupsByRef}); + Object.assign(groupCategory, {groups: groupRefs}); } groupCategory = thing; - groupsByRef = []; + groupRefs = []; } else { - groupsByRef.push(T.Thing.getReference(thing)); + groupRefs.push(Thing.getReference(thing)); } } if (groupCategory) { - Object.assign(groupCategory, {groupsByRef}); + Object.assign(groupCategory, {groups: groupRefs}); } const groupData = results.filter((x) => x instanceof T.Group); @@ -1462,45 +1462,45 @@ export function filterDuplicateDirectories(wikiData) { export function filterReferenceErrors(wikiData) { const referenceSpec = [ ['wikiInfo', processWikiInfoDocument, { - divideTrackListsByGroupsByRef: 'group', + divideTrackListsByGroups: 'group', }], ['albumData', processAlbumDocument, { - artistContribsByRef: '_contrib', - coverArtistContribsByRef: '_contrib', - trackCoverArtistContribsByRef: '_contrib', - wallpaperArtistContribsByRef: '_contrib', - bannerArtistContribsByRef: '_contrib', - groupsByRef: 'group', - artTagsByRef: 'artTag', + artistContribs: '_contrib', + coverArtistContribs: '_contrib', + trackCoverArtistContribs: '_contrib', + wallpaperArtistContribs: '_contrib', + bannerArtistContribs: '_contrib', + groups: 'group', + artTags: 'artTag', }], ['trackData', processTrackDocument, { - artistContribsByRef: '_contrib', - contributorContribsByRef: '_contrib', - coverArtistContribsByRef: '_contrib', - referencedTracksByRef: '_trackNotRerelease', - sampledTracksByRef: '_trackNotRerelease', - artTagsByRef: 'artTag', - originalReleaseTrackByRef: '_trackNotRerelease', + artistContribs: '_contrib', + contributorContribs: '_contrib', + coverArtistContribs: '_contrib', + referencedTracks: '_trackNotRerelease', + sampledTracks: '_trackNotRerelease', + artTags: 'artTag', + originalReleaseTrack: '_trackNotRerelease', }], ['groupCategoryData', processGroupCategoryDocument, { - groupsByRef: 'group', + groups: 'group', }], ['homepageLayout.rows', undefined, { - sourceGroupByRef: '_homepageSourceGroup', - sourceAlbumsByRef: 'album', + sourceGroup: '_homepageSourceGroup', + sourceAlbums: 'album', }], ['flashData', processFlashDocument, { - contributorContribsByRef: '_contrib', - featuredTracksByRef: 'track', + contributorContribs: '_contrib', + featuredTracks: 'track', }], ['flashActData', processFlashActDocument, { - flashesByRef: 'flash', + flashes: 'flash', }], ]; @@ -1532,7 +1532,7 @@ export function filterReferenceErrors(wikiData) { nest({message: `Reference errors in ${inspect(thing)}`}, ({push, filter}) => { for (const [property, findFnKey] of Object.entries(propSpec)) { - const value = thing[property]; + const value = CacheableObject.getUpdateValue(thing, property); if (value === undefined) { push(new TypeError(`Property ${colors.red(property)} isn't valid for ${colors.green(thing.constructor.name)}`)); @@ -1552,7 +1552,7 @@ export function filterReferenceErrors(wikiData) { if (alias) { // No need to check if the original exists here. Aliases are automatically // created from a field on the original, so the original certainly exists. - const original = find.artist(alias.aliasedArtistRef, wikiData.artistData, {mode: 'quiet'}); + const original = alias.aliasedArtist; throw new Error(`Reference ${colors.red(contribRef.who)} is to an alias, should be ${colors.green(original.name)}`); } @@ -1573,12 +1573,13 @@ export function filterReferenceErrors(wikiData) { case '_trackNotRerelease': findFn = trackRef => { const track = find.track(trackRef, wikiData.trackData, {mode: 'error'}); + const originalRef = track && CacheableObject.getUpdateValue(track, 'originalReleaseTrack'); - if (track?.originalReleaseTrackByRef) { + if (originalRef) { // It's possible for the original to not actually exist, in this case. // It should still be reported since the 'Originally Released As' field // was present. - const original = find.track(track.originalReleaseTrackByRef, wikiData.trackData, {mode: 'quiet'}); + const original = find.track(originalRef, wikiData.trackData, {mode: 'quiet'}); // Prefer references by name, but only if it's unambiguous. const originalByName = @@ -1591,7 +1592,7 @@ export function filterReferenceErrors(wikiData) { ? colors.green(original.name) : original ? colors.green('track:' + original.directory) - : colors.green(track.originalReleaseTrackByRef)); + : colors.green(originalRef)); throw new Error(`Reference ${colors.red(trackRef)} is to a rerelease, should be ${shouldBeMessage}`); } @@ -1606,7 +1607,7 @@ export function filterReferenceErrors(wikiData) { } const suppress = fn => conditionallySuppressError(error => { - if (property === 'sampledTracksByRef') { + if (property === 'sampledTracks') { // Suppress "didn't match anything" errors in particular, just for samples. // In hsmusic-data we have a lot of "stub" sample data which don't have // corresponding tracks yet, so it won't be useful to report such reference -- cgit 1.3.0-6-gf8a5 From fdd8f355bfe0992fc340f800297df524276b1946 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Mon, 18 Sep 2023 16:05:05 -0300 Subject: data: Track.alwaysReferencedByDirectory flag & field --- src/data/yaml.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 35943199..07e0a3d2 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -338,6 +338,8 @@ export const processTrackDocument = makeProcessDocument(T.Track, { coverArtFileExtension: 'Cover Art File Extension', hasCoverArt: 'Has Cover Art', + alwaysReferenceByDirectory: 'Always Reference By Directory', + lyrics: 'Lyrics', commentary: 'Commentary', additionalFiles: 'Additional Files', -- cgit 1.3.0-6-gf8a5 From 3a871cf43a11b87392d26320c736b516925da684 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 11 Oct 2023 14:32:28 -0300 Subject: implement flash act pages, rework flash sidebar layout --- src/data/yaml.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index c799be5f..0ecc1f1e 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -434,8 +434,10 @@ export const processFlashDocument = makeProcessDocument(T.Flash, { export const processFlashActDocument = makeProcessDocument(T.FlashAct, { propertyFieldMapping: { name: 'Act', + directory: 'Directory', + color: 'Color', - anchor: 'Anchor', + jump: 'Jump', jumpColor: 'Jump Color', }, -- cgit 1.3.0-6-gf8a5 From e842ce93e6405334b6ef475ec1db41e051cfd2b5 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 11 Oct 2023 14:49:43 -0300 Subject: data: use flash act directory for better determinism --- src/data/yaml.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 0ecc1f1e..a2811d43 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -1391,6 +1391,7 @@ export function filterDuplicateDirectories(wikiData) { 'albumData', 'artTagData', 'flashData', + 'flashActData', 'groupData', 'newsData', 'trackData', -- cgit 1.3.0-6-gf8a5 From 167e3ba07b54e6b9b780258fe8c10abd1ad80c2f Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 18 Oct 2023 14:30:21 -0300 Subject: yaml: cosmetic code clean-up --- src/data/yaml.js | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index a2811d43..33ca736d 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -59,7 +59,7 @@ export const DATA_STATIC_PAGE_DIRECTORY = 'static-page'; // document and apply the configuration passed to makeProcessDocument in order // to construct a Thing subclass. function makeProcessDocument( - thingClass, + thingConstructor, { // Optional early step for transforming field values before providing them // to the Thing's update() method. This is useful when the input format @@ -110,7 +110,7 @@ function makeProcessDocument( invalidFieldCombinations = [], } ) { - if (!thingClass) { + if (!thingConstructor) { throw new Error(`Missing Thing class`); } @@ -152,7 +152,7 @@ function makeProcessDocument( .filter((field) => !knownFields.includes(field)); if (!empty(unknownFields)) { - throw new makeProcessDocument.UnknownFieldsError(unknownFields); + aggregate.push(new UnknownFieldsError(unknownFields)); } const presentFields = Object.keys(document); @@ -162,18 +162,16 @@ function makeProcessDocument( for (const {message, fields} of invalidFieldCombinations) { const fieldsPresent = presentFields.filter(field => fields.includes(field)); - if (fieldsPresent.length <= 1) { - continue; + if (fieldsPresent.length >= 2) { + fieldCombinationErrors.push( + new FieldCombinationError( + filterProperties(document, fieldsPresent), + message)); } - - fieldCombinationErrors.push( - new makeProcessDocument.FieldCombinationError( - filterProperties(document, fieldsPresent), - message)); } if (!empty(fieldCombinationErrors)) { - throw new makeProcessDocument.FieldCombinationsError(fieldCombinationErrors); + aggregate.push(new FieldCombinationAggregateError(fieldCombinationErrors)); } const fieldValues = {}; @@ -193,9 +191,9 @@ function makeProcessDocument( sourceProperties[property] = value; } - const thing = Reflect.construct(thingClass, []); + const thing = Reflect.construct(thingConstructor, []); - withAggregate({message: `Errors applying ${colors.green(thingClass.name)} properties`}, ({call}) => { + withAggregate({message: `Errors applying ${colors.green(thingConstructor.name)} properties`}, ({call}) => { for (const [property, value] of Object.entries(sourceProperties)) { call(() => (thing[property] = value)); } @@ -212,20 +210,20 @@ function makeProcessDocument( return fn; } -makeProcessDocument.UnknownFieldsError = class UnknownFieldsError extends Error { +export class UnknownFieldsError extends Error { constructor(fields) { super(`Unknown fields present: ${fields.join(', ')}`); this.fields = fields; } -}; +} -makeProcessDocument.FieldCombinationsError = class FieldCombinationsError extends AggregateError { +export class FieldCombinationAggregateError extends AggregateError { constructor(errors) { super(errors, `Errors in combinations of fields present`); } -}; +} -makeProcessDocument.FieldCombinationError = class FieldCombinationError extends Error { +export class FieldCombinationError extends Error { constructor(fields, message) { const fieldNames = Object.keys(fields); const combinePart = `Don't combine ${fieldNames.map(field => colors.red(field)).join(', ')}`; @@ -933,6 +931,10 @@ export const dataSteps = [ { title: `Process homepage layout file`, + + // Kludge: This benefits from the same headerAndEntries style messaging as + // albums and tracks (for example), but that document mode is designed to + // support multiple files, and only one is actually getting processed here. files: [HOMEPAGE_LAYOUT_DATA_FILE], documentMode: documentModes.headerAndEntries, -- cgit 1.3.0-6-gf8a5 From d8d877b63eec2e7c1d1afbca84b7f3cf6d24ca35 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 18 Oct 2023 14:32:00 -0300 Subject: yaml: filter and skip properties, not entire documents --- src/data/yaml.js | 260 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 164 insertions(+), 96 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 33ca736d..06ef5546 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -10,7 +10,12 @@ import yaml from 'js-yaml'; import {colors, ENABLE_COLOR, logInfo, logWarn} from '#cli'; import find, {bindFind} from '#find'; import {traverse} from '#node-utils'; -import T, {CacheableObject, Thing} from '#things'; + +import T, { + CacheableObject, + CacheableObjectPropertyValueError, + Thing, +} from '#things'; import { conditionallySuppressError, @@ -144,6 +149,25 @@ function makeProcessDocument( }; const fn = decorateErrorWithName((document) => { + const nameField = propertyFieldMapping['name']; + const namePart = + (nameField + ? (document[nameField] + ? ` named ${colors.green(`"${document[nameField]}"`)}` + : ` (name field, "${nameField}", not specified)`) + : ``); + + const constructorPart = + (thingConstructor[Thing.friendlyName] + ? colors.green(thingConstructor[Thing.friendlyName]) + : thingConstructor.name + ? colors.green(thingConstructor.name) + : `document`); + + const aggregate = openAggregate({ + message: `Errors processing ${constructorPart}` + namePart, + }); + const documentEntries = Object.entries(document) .filter(([field]) => !ignoredFields.includes(field)); @@ -187,19 +211,31 @@ function makeProcessDocument( const sourceProperties = {}; for (const [field, value] of Object.entries(fieldValues)) { - const property = fieldPropertyMapping[field]; - sourceProperties[property] = value; + if (Object.hasOwn(fieldPropertyMapping, field)) { + const property = fieldPropertyMapping[field]; + sourceProperties[property] = value; + } } const thing = Reflect.construct(thingConstructor, []); - withAggregate({message: `Errors applying ${colors.green(thingConstructor.name)} properties`}, ({call}) => { - for (const [property, value] of Object.entries(sourceProperties)) { - call(() => (thing[property] = value)); + const fieldValueErrors = []; + + // This for loop would like to certify itself as "not into capitalism". + for (const [property, value] of Object.entries(sourceProperties)) { + const field = propertyFieldMapping[property]; + try { + thing[property] = value; + } catch (caughtError) { + fieldValueErrors.push(new FieldValueError(field, property, value, caughtError)); } - }); + } - return thing; + if (!empty(fieldValueErrors)) { + aggregate.push(new FieldValueAggregateError(thingConstructor, fieldValueErrors)); + } + + return {thing, aggregate}; }); Object.assign(fn, { @@ -212,7 +248,7 @@ function makeProcessDocument( export class UnknownFieldsError extends Error { constructor(fields) { - super(`Unknown fields present: ${fields.join(', ')}`); + super(`Unknown fields present: ${fields.map(field => colors.red(field)).join(', ')}`); this.fields = fields; } } @@ -240,6 +276,25 @@ export class FieldCombinationError extends Error { } } +export class FieldValueAggregateError extends AggregateError { + constructor(thingConstructor, errors) { + super(errors, `Errors processing field values for ${colors.green(thingConstructor.name)}`); + } +} + +export class FieldValueError extends Error { + constructor(field, property, value, caughtError) { + const cause = + (caughtError instanceof CacheableObjectPropertyValueError + ? caughtError.cause + : caughtError); + + super( + `Failed to set ${colors.green(`"${field}"`)} field (${colors.green(property)}) to ${inspect(value)}`, + {cause}); + } +} + export const processAlbumDocument = makeProcessDocument(T.Album, { fieldTransformations: { 'Artists': parseContributors, @@ -1023,8 +1078,8 @@ export async function loadAndProcessDataDocuments({dataPath}) { for (const dataStep of dataSteps) { await processDataAggregate.nestAsync( - {message: `Errors during data step: ${dataStep.title}`}, - async ({call, callAsync, map, mapAsync, nest}) => { + {message: `Errors during data step: ${colors.bright(dataStep.title)}`}, + async ({call, callAsync, map, mapAsync, push, nest}) => { const {documentMode} = dataStep; if (!Object.values(documentModes).includes(documentMode)) { @@ -1149,32 +1204,52 @@ export async function loadAndProcessDataDocuments({dataPath}) { return; } - const yamlResult = - documentMode === documentModes.oneDocumentTotal - ? call(yaml.load, readResult) - : call(yaml.loadAll, readResult); + let processResults; - if (!yamlResult) { - return; - } + switch (documentMode) { + case documentModes.oneDocumentTotal: { + const yamlResult = call(yaml.load, readResult); - let processResults; + if (!yamlResult) { + processResults = null; + break; + } + + const {thing, aggregate} = + dataStep.processDocument(yamlResult); + + processResults = thing; + + call(() => aggregate.close()); - if (documentMode === documentModes.oneDocumentTotal) { - nest({message: `Errors processing document`}, ({call}) => { - processResults = call(dataStep.processDocument, yamlResult); - }); - } else { - const {documents, aggregate: aggregate1} = filterBlankDocuments(yamlResult); - call(aggregate1.close); - - const {result, aggregate: aggregate2} = mapAggregate( - documents, - decorateErrorWithIndex(dataStep.processDocument), - {message: `Errors processing documents`}); - call(aggregate2.close); - - processResults = result; + break; + } + + case documentModes.allInOne: { + const yamlResults = call(yaml.loadAll, readResult); + + if (!yamlResults) { + processResults = []; + return; + } + + const {documents, aggregate: filterAggregate} = + filterBlankDocuments(yamlResults); + + call(filterAggregate.close); + + processResults = []; + + map(documents, decorateErrorWithIndex(document => { + const {thing, aggregate} = + dataStep.processDocument(document); + + processResults.push(thing); + aggregate.close(); + }), {message: `Errors processing documents`}); + + break; + } } if (!processResults) return; @@ -1232,81 +1307,74 @@ export async function loadAndProcessDataDocuments({dataPath}) { return {file, documents: filteredDocuments}; }); - let processResults; + const processResults = []; - if (documentMode === documentModes.headerAndEntries) { - nest({message: `Errors processing data files as valid documents`}, ({call, map}) => { - processResults = []; + switch (documentMode) { + case documentModes.headerAndEntries: + map(yamlResults, decorateErrorWithFile(({documents}) => { + const headerDocument = documents[0]; + const entryDocuments = documents.slice(1).filter(Boolean); - yamlResults.forEach(({file, documents}) => { - const [headerDocument, ...entryDocuments] = documents; + if (!headerDocument) + throw new Error(`Missing header document (empty file or erroneously starting with "---"?)`); - if (!headerDocument) { - call(decorateErrorWithFile(() => { - throw new Error(`Missing header document (empty file or erroneously starting with "---"?)`); - }), {file}); - return; - } + // This'll be decorated with the file, and groups together any + // errors from processing the header and entry documents. + const fileAggregate = + openAggregate({message: `Errors processing documents`}); - const header = call( - decorateErrorWithFile(({document}) => - dataStep.processHeaderDocument(document)), - {file, document: headerDocument}); + const {thing: headerObject, aggregate: headerAggregate} = + dataStep.processHeaderDocument(headerDocument); - // Don't continue processing files whose header - // document is invalid - the entire file is excempt - // from data in this case. - if (!header) { - return; + try { + headerAggregate.close() + } catch (caughtError) { + caughtError.message = `(${colors.yellow(`header`)}) ${caughtError.message}`; + fileAggregate.push(caughtError); } - const entries = map( - entryDocuments - .filter(Boolean) - .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}); - }); - }); - } + const entryObjects = []; - if (documentMode === documentModes.onePerFile) { - nest({message: `Errors processing data files as valid documents`}, ({call}) => { - processResults = []; + for (let index = 0; index < entryDocuments.length; index++) { + const entryDocument = entryDocuments[index]; - yamlResults.forEach(({file, documents}) => { - if (documents.length > 1) { - call(decorateErrorWithFile(() => { - throw new Error(`Only expected one document to be present per file`); - }), {file}); - return; - } else if (empty(documents) || !documents[0]) { - call(decorateErrorWithFile(() => { - throw new Error(`Expected a document, this file is empty`); - }), {file}); - } + const {thing: entryObject, aggregate: entryAggregate} = + dataStep.processEntryDocument(entryDocument); - const result = call( - decorateErrorWithFile(({document}) => - dataStep.processDocument(document)), - {file, document: documents[0]}); + entryObjects.push(entryObject); - if (!result) { - return; + try { + entryAggregate.close(); + } catch (caughtError) { + caughtError.message = `(${colors.yellow(`entry #${index + 1}`)}) ${caughtError.message}`; + fileAggregate.push(caughtError); + } } - processResults.push(result); - }); - }); + processResults.push({ + header: headerObject, + entries: entryObjects, + }); + + fileAggregate.close(); + }), {message: `Errors processing documents in data files`}); + break; + + case documentModes.onePerFile: + map(yamlResults, decorateErrorWithFile(({documents}) => { + if (documents.length > 1) + throw new Error(`Only expected one document to be present per file, got ${documents.length} here`); + + if (empty(documents) || !documents[0]) + throw new Error(`Expected a document, this file is empty`); + + const {thing, aggregate} = + dataStep.processDocument(documents[0]); + + processResults.push(thing); + aggregate.close(); + }), {message: `Errors processing data files as valid documents`}); + break; } const saveResult = call(dataStep.save, processResults); -- cgit 1.3.0-6-gf8a5 From 84d22c117d6deabd53aaee1546e3a99f5d6049c7 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Wed, 18 Oct 2023 14:54:38 -0300 Subject: yaml: track skipped fields separately & report summary at bottom --- src/data/yaml.js | 80 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 16 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 06ef5546..f49f48dd 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -171,12 +171,18 @@ function makeProcessDocument( const documentEntries = Object.entries(document) .filter(([field]) => !ignoredFields.includes(field)); + const skippedFields = new Set(); + const unknownFields = documentEntries .map(([field]) => field) .filter((field) => !knownFields.includes(field)); if (!empty(unknownFields)) { aggregate.push(new UnknownFieldsError(unknownFields)); + + for (const field of unknownFields) { + skippedFields.add(field); + } } const presentFields = Object.keys(document); @@ -187,10 +193,17 @@ function makeProcessDocument( const fieldsPresent = presentFields.filter(field => fields.includes(field)); if (fieldsPresent.length >= 2) { - fieldCombinationErrors.push( - new FieldCombinationError( - filterProperties(document, fieldsPresent), - message)); + const filteredDocument = + filterProperties( + document, + fieldsPresent, + {preserveOriginalOrder: true}); + + fieldCombinationErrors.push(new FieldCombinationError(filteredDocument, message)); + + for (const field of Object.keys(filteredDocument)) { + skippedFields.add(field); + } } } @@ -201,6 +214,7 @@ function makeProcessDocument( const fieldValues = {}; for (const [field, value] of documentEntries) { + if (skippedFields.has(field)) continue; if (Object.hasOwn(fieldTransformations, field)) { fieldValues[field] = fieldTransformations[field](value); } else { @@ -211,10 +225,8 @@ function makeProcessDocument( const sourceProperties = {}; for (const [field, value] of Object.entries(fieldValues)) { - if (Object.hasOwn(fieldPropertyMapping, field)) { - const property = fieldPropertyMapping[field]; - sourceProperties[property] = value; - } + const property = fieldPropertyMapping[field]; + sourceProperties[property] = value; } const thing = Reflect.construct(thingConstructor, []); @@ -227,6 +239,7 @@ function makeProcessDocument( try { thing[property] = value; } catch (caughtError) { + skippedFields.add(field); fieldValueErrors.push(new FieldValueError(field, property, value, caughtError)); } } @@ -235,6 +248,15 @@ function makeProcessDocument( aggregate.push(new FieldValueAggregateError(thingConstructor, fieldValueErrors)); } + if (skippedFields.size >= 1) { + aggregate.push( + new SkippedFieldsSummaryError( + filterProperties( + document, + Array.from(skippedFields), + {preserveOriginalOrder: true}))); + } + return {thing, aggregate}; }); @@ -248,30 +270,37 @@ function makeProcessDocument( export class UnknownFieldsError extends Error { constructor(fields) { - super(`Unknown fields present: ${fields.map(field => colors.red(field)).join(', ')}`); + super(`Unknown fields ignored: ${fields.map(field => colors.red(field)).join(', ')}`); this.fields = fields; } } export class FieldCombinationAggregateError extends AggregateError { constructor(errors) { - super(errors, `Errors in combinations of fields present`); + super(errors, `Invalid field combinations - all involved fields ignored`); } } export class FieldCombinationError extends Error { constructor(fields, message) { const fieldNames = Object.keys(fields); - const combinePart = `Don't combine ${fieldNames.map(field => colors.red(field)).join(', ')}`; - const messagePart = + const mainMessage = `Don't combine ${fieldNames.map(field => colors.red(field)).join(', ')}`; + + const causeMessage = (typeof message === 'function' - ? `: ${message(fields)}` + ? message(fields) : typeof message === 'string' - ? `: ${message}` - : ``); + ? message + : null); + + super(mainMessage, { + cause: + (causeMessage + ? new Error(causeMessage) + : null), + }); - super(combinePart + messagePart); this.fields = fields; } } @@ -295,6 +324,25 @@ export class FieldValueError extends Error { } } +export class SkippedFieldsSummaryError extends Error { + constructor(filteredDocument) { + const entries = Object.entries(filteredDocument); + + const lines = + entries.map(([field, value]) => + ` - ${field}: ` + + inspect(value) + .split('\n') + .map((line, index) => index === 0 ? line : ` ${line}`) + .join('\n')); + + super( + colors.bright(colors.yellow(`Altogether, skipped ${entries.length === 1 ? `1 field` : `${entries.length} fields`}:\n`)) + + lines.join('\n') + '\n' + + colors.bright(colors.yellow(`See above errors for details.`))); + } +} + export const processAlbumDocument = makeProcessDocument(T.Album, { fieldTransformations: { 'Artists': parseContributors, -- cgit 1.3.0-6-gf8a5 From 66d529179fc1896141876988dbe2a037f58b393b Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 24 Oct 2023 09:25:12 -0300 Subject: yaml: remove cruft, support blank list items --- src/data/yaml.js | 58 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 26 deletions(-) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index f49f48dd..bf63f05d 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -213,13 +213,36 @@ function makeProcessDocument( const fieldValues = {}; - for (const [field, value] of documentEntries) { + for (const [field, documentValue] of documentEntries) { if (skippedFields.has(field)) continue; - if (Object.hasOwn(fieldTransformations, field)) { - fieldValues[field] = fieldTransformations[field](value); - } else { - fieldValues[field] = value; + + // This variable would like to certify itself as "not into capitalism". + let propertyValue = + (Object.hasOwn(fieldTransformations, field) + ? fieldTransformations[field](documentValue) + : documentValue); + + // Completely blank items in a YAML list are read as null. + // They're handy to have around when filling out a document and shouldn't + // be considered an error (or data at all). + if (Array.isArray(propertyValue)) { + const wasEmpty = empty(propertyValue); + + propertyValue = + propertyValue.filter(item => item !== null); + + const isEmpty = empty(propertyValue); + + // Don't set arrays which are empty as a result of the above filter. + // Arrays which were originally empty, i.e. `Field: []`, are still + // valid data, but if it's just an array not containing any filled out + // items, it should be treated as a placeholder and skipped over. + if (isEmpty && !wasEmpty) { + propertyValue = null; + } } + + fieldValues[field] = propertyValue; } const sourceProperties = {}; @@ -233,7 +256,6 @@ function makeProcessDocument( const fieldValueErrors = []; - // This for loop would like to certify itself as "not into capitalism". for (const [property, value] of Object.entries(sourceProperties)) { const field = propertyFieldMapping[property]; try { @@ -700,33 +722,17 @@ export function parseContributors(contributors) { return contributors; } - if (contributors.length === 1 && contributors[0].startsWith('')) { - const arr = []; - arr.textContent = contributors[0]; - return arr; - } - contributors = contributors.map((contrib) => { - // 8asically, the format is "Who (What)", or just "Who". 8e sure to - // keep in mind that "what" doesn't necessarily have a value! + if (typeof contrib !== 'string') return contrib; + const match = contrib.match(/^(.*?)( \((.*)\))?$/); - if (!match) { - return contrib; - } + if (!match) return contrib; + const who = match[1]; const what = match[3] || null; return {who, what}; }); - const badContributor = contributors.find((val) => typeof val === 'string'); - if (badContributor) { - throw new Error(`Incorrectly formatted contribution: "${badContributor}".`); - } - - if (contributors.length === 1 && contributors[0].who === 'none') { - return null; - } - return contributors; } -- cgit 1.3.0-6-gf8a5 From f461941ac3d39b307ac32e21f9ff41b47fba638b Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 24 Oct 2023 10:47:40 -0300 Subject: data, yaml: new flash act field List Termonology / listTerminology --- src/data/yaml.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index bf63f05d..f12c4c31 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -560,6 +560,7 @@ export const processFlashActDocument = makeProcessDocument(T.FlashAct, { directory: 'Directory', color: 'Color', + listTerminology: 'List Terminology', jump: 'Jump', jumpColor: 'Jump Color', -- cgit 1.3.0-6-gf8a5 From 6c0c1525a0e924896a2a593fc05633e442a80413 Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 24 Oct 2023 10:49:05 -0300 Subject: yaml: check artists for duplicate directories --- src/data/yaml.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index f12c4c31..16303a64 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -1515,6 +1515,7 @@ export function filterDuplicateDirectories(wikiData) { const deduplicateSpec = [ 'albumData', 'artTagData', + 'artistData', 'flashData', 'flashActData', 'groupData', -- cgit 1.3.0-6-gf8a5 From a80dcfd176c41cef1995f5349a1464d4746badbd Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 24 Oct 2023 11:33:25 -0300 Subject: data, yaml: new flash Color / color field --- src/data/yaml.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/data/yaml.js') diff --git a/src/data/yaml.js b/src/data/yaml.js index 16303a64..f7856cb7 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -544,6 +544,7 @@ export const processFlashDocument = makeProcessDocument(T.Flash, { name: 'Flash', directory: 'Directory', page: 'Page', + color: 'Color', urls: 'URLs', date: 'Date', -- cgit 1.3.0-6-gf8a5