diff options
Diffstat (limited to 'src/data/checks.js')
-rw-r--r-- | src/data/checks.js | 187 |
1 files changed, 162 insertions, 25 deletions
diff --git a/src/data/checks.js b/src/data/checks.js index ad621bab..25863d2d 100644 --- a/src/data/checks.js +++ b/src/data/checks.js @@ -9,7 +9,6 @@ import {compareArrays, cut, cutStart, empty, getNestedProp, iterateMultiline} from '#sugar'; import Thing from '#thing'; import thingConstructors from '#things'; -import {commentaryRegexCaseSensitive} from '#wiki-data'; import { annotateErrorWithIndex, @@ -20,6 +19,12 @@ import { withAggregate, } from '#aggregate'; +import { + combineWikiDataArrays, + commentaryRegexCaseSensitive, + oldStyleLyricsDetectionRegex, +} from '#wiki-data'; + function inspect(value, opts = {}) { return nodeInspect(value, {colors: ENABLE_COLOR, ...opts}); } @@ -50,7 +55,7 @@ export function reportDirectoryErrors(wikiData, { if (!thingData) continue; for (const thing of thingData) { - if (findSpec.include && !findSpec.include(thing)) { + if (findSpec.include && !findSpec.include(thing, thingConstructors)) { continue; } @@ -172,6 +177,7 @@ function getFieldPropertyMessage(yamlDocumentSpec, property) { // any errors). At the same time, we remove errored references from the thing's // data array. export function filterReferenceErrors(wikiData, { + find, bindFind, }) { const referenceSpec = [ @@ -183,9 +189,14 @@ export function filterReferenceErrors(wikiData, { bannerArtistContribs: '_contrib', groups: 'group', artTags: '_artTag', + referencedArtworks: '_artwork', commentary: '_commentary', }], + ['artTagData', { + directDescendantArtTags: 'artTag', + }], + ['flashData', { commentary: '_commentary', }], @@ -194,7 +205,13 @@ export function filterReferenceErrors(wikiData, { groups: 'group', }], - ['homepageLayout.rows', { + ['homepageLayout.sections.rows', { + _include: row => row.type === 'album carousel', + albums: 'album', + }], + + ['homepageLayout.sections.rows', { + _include: row => row.type === 'album grid', sourceGroup: '_homepageSourceGroup', sourceAlbums: 'album', }], @@ -208,14 +225,19 @@ export function filterReferenceErrors(wikiData, { flashes: 'flash', }], + ['groupData', { + serieses: '_serieses', + }], + ['trackData', { artistContribs: '_contrib', contributorContribs: '_contrib', coverArtistContribs: '_contrib', - referencedTracks: '_trackNotRerelease', - sampledTracks: '_trackNotRerelease', + referencedTracks: '_trackMainReleasesOnly', + sampledTracks: '_trackMainReleasesOnly', artTags: '_artTag', - originalReleaseTrack: '_trackNotRerelease', + referencedArtworks: '_artwork', + mainReleaseTrack: '_trackMainReleasesOnly', commentary: '_commentary', }], @@ -230,11 +252,23 @@ export function filterReferenceErrors(wikiData, { const aggregate = openAggregate({message: `Errors validating between-thing references in data`}); for (const [thingDataProp, propSpec] of referenceSpec) { const thingData = getNestedProp(wikiData, thingDataProp); - const things = Array.isArray(thingData) ? thingData : [thingData]; + const things = + (Array.isArray(thingData) + ? thingData.flat(Infinity) + : [thingData]); + aggregate.nest({message: `Reference errors in ${colors.green('wikiData.' + thingDataProp)}`}, ({nest}) => { for (const thing of things) { + if (propSpec._include && !propSpec._include(thing)) { + continue; + } + nest({message: `Reference errors in ${inspect(thing)}`}, ({nest, push, filter}) => { for (const [property, findFnKey] of Object.entries(propSpec)) { + if (property === '_include') { + continue; + } + let value = CacheableObject.getUpdateValue(thing, property); let writeProperty = true; @@ -258,6 +292,15 @@ export function filterReferenceErrors(wikiData, { // need writing, humm...) writeProperty = false; break; + + case '_serieses': + if (value) { + // Doesn't report on which series has the error, but... + value = value.flatMap(series => series.albums); + } + + writeProperty = false; + break; } if (value === undefined) { @@ -272,6 +315,21 @@ export function filterReferenceErrors(wikiData, { let findFn; switch (findFnKey) { + case '_artwork': { + const mixed = + find.mixed({ + album: find.albumPrimaryArtwork, + track: find.trackPrimaryArtwork, + }); + + const data = + wikiData.artworkData; + + findFn = ref => mixed(ref.reference, data, {mode: 'error'}); + + break; + } + case '_artTag': findFn = boundFind.artTag; break; @@ -294,29 +352,36 @@ export function filterReferenceErrors(wikiData, { }; break; - case '_trackNotRerelease': + case '_serieses': + findFn = boundFind.album; + break; + + case '_trackArtwork': + findFn = ref => boundFind.track(ref.reference); + break; + + case '_trackMainReleasesOnly': findFn = trackRef => { const track = boundFind.track(trackRef); - const originalRef = track && CacheableObject.getUpdateValue(track, 'originalReleaseTrack'); + const mainRef = track && CacheableObject.getUpdateValue(track, 'mainReleaseTrack'); - 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 = boundFind.track(originalRef, {mode: 'quiet'}); + if (mainRef) { + // It's possible for the main release to not actually exist, in this case. + // It should still be reported since the 'Main Release' field was present. + const main = boundFind.track(mainRef, {mode: 'quiet'}); // Prefer references by name, but only if it's unambiguous. - const originalByName = - (original - ? boundFind.track(original.name, {mode: 'quiet'}) + const mainByName = + (main + ? boundFind.track(main.name, {mode: 'quiet'}) : null); const shouldBeMessage = - (originalByName - ? colors.green(original.name) - : original - ? colors.green('track:' + original.directory) - : colors.green(originalRef)); + (mainByName + ? colors.green(main.name) + : main + ? colors.green('track:' + main.directory) + : colors.green(mainRef)); throw new Error(`Reference ${colors.red(trackRef)} is to a rerelease, should be ${shouldBeMessage}`); } @@ -331,6 +396,10 @@ export function filterReferenceErrors(wikiData, { } const suppress = fn => conditionallySuppressError(error => { + // We're not suppressing any errors at the moment. + // An old suppression is kept below for reference. + + /* 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 @@ -343,6 +412,7 @@ export function filterReferenceErrors(wikiData, { return true; } } + */ return false; }, fn); @@ -503,12 +573,22 @@ export function reportContentTextErrors(wikiData, { annotation: 'commentary annotation', }; + const newStyleLyricsShape = { + body: 'lyrics body', + artistDisplayText: 'lyrics artist display text', + annotation: 'lyrics annotation', + }; + const contentTextSpec = [ ['albumData', { additionalFiles: additionalFileShape, commentary: commentaryShape, }], + ['artTagData', { + description: '_content', + }], + ['artistData', { contextNotes: '_content', }], @@ -544,7 +624,8 @@ export function reportContentTextErrors(wikiData, { ['trackData', { additionalFiles: additionalFileShape, commentary: commentaryShape, - lyrics: '_content', + creditSources: commentaryShape, + lyrics: '_lyrics', midiProjectFiles: additionalFileShape, sheetMusicFiles: additionalFileShape, }], @@ -667,8 +748,9 @@ export function reportContentTextErrors(wikiData, { for (const thing of things) { nest({message: `Content text errors in ${inspect(thing)}`}, ({nest, push}) => { - for (const [property, shape] of Object.entries(propSpec)) { - const value = thing[property]; + for (let [property, shape] of Object.entries(propSpec)) { + const rawValue = CacheableObject.getUpdateValue(thing, property); + let value = thing[property]; if (value === undefined) { push(new TypeError(`Property ${colors.red(property)} isn't valid for ${colors.green(thing.constructor.name)}`)); @@ -679,6 +761,15 @@ export function reportContentTextErrors(wikiData, { continue; } + if (shape === '_lyrics') { + if (oldStyleLyricsDetectionRegex.test(rawValue)) { + value = rawValue; + shape = '_content'; + } else { + shape = newStyleLyricsShape; + } + } + const fieldPropertyMessage = getFieldPropertyMessage( thing.constructor[Thing.yamlDocumentSpec], @@ -722,3 +813,49 @@ export function reportContentTextErrors(wikiData, { } }); } + +export function reportOrphanedArtworks(wikiData) { + const aggregate = + openAggregate({message: `Artwork objects are orphaned`}); + + const assess = ({ + message, + filterThing, + filterContribs, + link, + }) => { + aggregate.nest({message: `Orphaned ${message}`}, ({push}) => { + const ostensibleArtworks = + wikiData.artworkData + .filter(artwork => + artwork.thing instanceof filterThing && + artwork.artistContribsFromThingProperty === filterContribs); + + const orphanedArtworks = + ostensibleArtworks + .filter(artwork => !artwork.thing[link].includes(artwork)); + + for (const artwork of orphanedArtworks) { + push(new Error(`Orphaned: ${inspect(artwork)}`)); + } + }); + }; + + const {Album, Track} = thingConstructors; + + assess({ + message: `album cover artworks`, + filterThing: Album, + filterContribs: 'coverArtistContribs', + link: 'coverArtworks', + }); + + assess({ + message: `track artworks`, + filterThing: Track, + filterContribs: 'coverArtistContribs', + link: 'trackArtworks', + }); + + aggregate.close(); +} |