diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/content/dependencies/generateCommentaryEntry.js | 13 | ||||
-rw-r--r-- | src/content/dependencies/transformContent.js | 57 | ||||
-rw-r--r-- | src/data/composite/data/index.js | 1 | ||||
-rw-r--r-- | src/data/composite/data/withUniqueItemsOnly.js | 40 | ||||
-rw-r--r-- | src/data/composite/wiki-data/withParsedCommentaryEntries.js | 40 | ||||
-rw-r--r-- | src/data/composite/wiki-properties/commentatorArtists.js | 28 | ||||
-rw-r--r-- | src/data/yaml.js | 24 | ||||
-rw-r--r-- | src/util/wiki-data.js | 8 |
8 files changed, 163 insertions, 48 deletions
diff --git a/src/content/dependencies/generateCommentaryEntry.js b/src/content/dependencies/generateCommentaryEntry.js index b265ed41..0b2b2558 100644 --- a/src/content/dependencies/generateCommentaryEntry.js +++ b/src/content/dependencies/generateCommentaryEntry.js @@ -1,3 +1,5 @@ +import {empty} from '#sugar'; + export default { contentDependencies: [ 'generateColorStyleVariables', @@ -8,9 +10,10 @@ export default { extraDependencies: ['html', 'language'], relations: (relation, entry) => ({ - artistLink: - (entry.artist && !entry.artistDisplayText - ? relation('linkArtist', entry.artist) + artistLinks: + (!empty(entry.artists) && !entry.artistDisplayText + ? entry.artists + .map(artist => relation('linkArtist', artist)) : null), artistsContent: @@ -45,8 +48,8 @@ export default { html.tag('span', {class: 'commentary-entry-artists'}, (relations.artistsContent ? relations.artistsContent.slot('mode', 'inline') - : relations.artistLink - ? relations.artistLink + : relations.artistLinks + ? language.formatConjunctionList(relations.artistLinks) : language.$('misc.artistCommentary.entry.title.noArtists'))); const accentParts = ['misc.artistCommentary.entry.title.accent']; diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index a85ac158..b0a7796c 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -1,7 +1,7 @@ import {bindFind} from '#find'; import {parseInput} from '#replacer'; -import {marked} from 'marked'; +import {Marked} from 'marked'; export const replacerSpec = { album: { @@ -147,6 +147,29 @@ const linkIndexRelationMap = { newsIndex: 'linkNewsIndex', }; +const commonMarkedOptions = { + headerIds: false, + mangle: false, +}; + +const multilineMarked = new Marked({ + ...commonMarkedOptions, +}); + +const inlineMarked = new Marked({ + ...commonMarkedOptions, + + renderer: { + paragraph(text) { + return text; + }, + }, +}); + +const lyricsMarked = new Marked({ + ...commonMarkedOptions, +}); + function getPlaceholder(node, content) { return {type: 'text', data: content.slice(node.i, node.iEnd)}; } @@ -447,21 +470,9 @@ export default { return link.data; } - // In inline mode, no further processing is needed! - - if (slots.mode === 'inline') { - return html.tags( - contentFromNodes.map(node => node.data), - {[html.joinChildren]: ''}); - } - - // Multiline mode has a secondary processing stage where it's passed... - // through marked! Rolling your own Markdown only gets you so far :D - - const markedOptions = { - headerIds: false, - mangle: false, - }; + // Content always goes through marked (i.e. parsing as Markdown). + // This does require some attention to detail, mostly to do with line + // breaks (in multiline mode) and extracting/re-inserting non-text nodes. // The content of non-text nodes can end up getting mangled by marked. // To avoid this, we replace them with mundane placeholders, then @@ -536,6 +547,16 @@ export default { return html.tags(tags, {[html.joinChildren]: ''}); }; + if (slots.mode === 'inline') { + const markedInput = + extractNonTextNodes(); + + const markedOutput = + inlineMarked.parse(markedInput); + + return reinsertNonTextNodes(markedOutput); + } + // This is separated into its own function just since we're gonna reuse // it in a minute if everything goes to heck in lyrics mode. const transformMultiline = () => { @@ -552,7 +573,7 @@ export default { .replace(/(?<=^>.*)\n+(?!^>)/gm, '\n\n'); const markedOutput = - marked.parse(markedInput, markedOptions); + multilineMarked.parse(markedInput); return reinsertNonTextNodes(markedOutput); } @@ -602,7 +623,7 @@ export default { }); const markedOutput = - marked.parse(markedInput, markedOptions); + lyricsMarked.parse(markedInput); return reinsertNonTextNodes(markedOutput); } diff --git a/src/data/composite/data/index.js b/src/data/composite/data/index.js index db1c37cc..e2927afd 100644 --- a/src/data/composite/data/index.js +++ b/src/data/composite/data/index.js @@ -11,3 +11,4 @@ export {default as withPropertiesFromObject} from './withPropertiesFromObject.js export {default as withPropertyFromList} from './withPropertyFromList.js'; export {default as withPropertyFromObject} from './withPropertyFromObject.js'; export {default as withUnflattenedList} from './withUnflattenedList.js'; +export {default as withUniqueItemsOnly} from './withUniqueItemsOnly.js'; diff --git a/src/data/composite/data/withUniqueItemsOnly.js b/src/data/composite/data/withUniqueItemsOnly.js new file mode 100644 index 00000000..7ee08b08 --- /dev/null +++ b/src/data/composite/data/withUniqueItemsOnly.js @@ -0,0 +1,40 @@ +// Excludes duplicate items from a list and provides the results, overwriting +// the list in-place, if possible. + +import {input, templateCompositeFrom} from '#composite'; +import {unique} from '#sugar'; + +export default templateCompositeFrom({ + annotation: `withUniqueItemsOnly`, + + inputs: { + list: input({type: 'array'}), + }, + + outputs: ({ + [input.staticDependency('list')]: list, + }) => [list ?? '#uniqueItems'], + + steps: () => [ + { + dependencies: [input('list')], + compute: (continuation, { + [input('list')]: list, + }) => continuation({ + ['#values']: + unique(list), + }), + }, + + { + dependencies: ['#values', input.staticDependency('list')], + compute: (continuation, { + '#values': values, + [input.staticDependency('list')]: list, + }) => continuation({ + [list ?? '#uniqueItems']: + values, + }), + }, + ], +}); diff --git a/src/data/composite/wiki-data/withParsedCommentaryEntries.js b/src/data/composite/wiki-data/withParsedCommentaryEntries.js index 7b1c9484..edfc9e3c 100644 --- a/src/data/composite/wiki-data/withParsedCommentaryEntries.js +++ b/src/data/composite/wiki-data/withParsedCommentaryEntries.js @@ -4,7 +4,12 @@ import {stitchArrays} from '#sugar'; import {isCommentary} from '#validators'; import {commentaryRegex} from '#wiki-data'; -import {fillMissingListItems, withPropertiesFromList} from '#composite/data'; +import { + fillMissingListItems, + withFlattenedList, + withPropertiesFromList, + withUnflattenedList, +} from '#composite/data'; import withResolvedReferenceList from './withResolvedReferenceList.js'; @@ -86,23 +91,42 @@ export default templateCompositeFrom({ list: '#rawMatches.groups', prefix: input.value('#entries'), properties: input.value([ - 'artistReference', + 'artistReferences', 'artistDisplayText', 'annotation', 'date', ]), }), - // The artistReference group will always have a value, since it's required + // The artistReferences group will always have a value, since it's required // for the line to match in the first place. + { + dependencies: ['#entries.artistReferences'], + compute: (continuation, { + ['#entries.artistReferences']: artistReferenceTexts, + }) => continuation({ + ['#entries.artistReferences']: + artistReferenceTexts + .map(text => text.split(',').map(ref => ref.trim())), + }), + }, + + withFlattenedList({ + list: '#entries.artistReferences', + }), + withResolvedReferenceList({ - list: '#entries.artistReference', + list: '#flattenedList', data: 'artistData', find: input.value(find.artist), notFoundMode: input.value('null'), + }), + + withUnflattenedList({ + list: '#resolvedReferenceList', }).outputs({ - '#resolvedReferenceList': '#entries.artist', + '#unflattenedList': '#entries.artists', }), fillMissingListItems({ @@ -127,7 +151,7 @@ export default templateCompositeFrom({ { dependencies: [ - '#entries.artist', + '#entries.artists', '#entries.artistDisplayText', '#entries.annotation', '#entries.date', @@ -135,7 +159,7 @@ export default templateCompositeFrom({ ], compute: (continuation, { - ['#entries.artist']: artist, + ['#entries.artists']: artists, ['#entries.artistDisplayText']: artistDisplayText, ['#entries.annotation']: annotation, ['#entries.date']: date, @@ -143,7 +167,7 @@ export default templateCompositeFrom({ }) => continuation({ ['#parsedCommentaryEntries']: stitchArrays({ - artist, + artists, artistDisplayText, annotation, date, diff --git a/src/data/composite/wiki-properties/commentatorArtists.js b/src/data/composite/wiki-properties/commentatorArtists.js index 8720e66d..f400bbfc 100644 --- a/src/data/composite/wiki-properties/commentatorArtists.js +++ b/src/data/composite/wiki-properties/commentatorArtists.js @@ -4,8 +4,10 @@ import {input, templateCompositeFrom} from '#composite'; import {unique} from '#sugar'; -import {exitWithoutDependency} from '#composite/control-flow'; -import {withPropertyFromList} from '#composite/data'; +import {exitWithoutDependency, exposeDependency} + from '#composite/control-flow'; +import {withFlattenedList, withPropertyFromList, withUniqueItemsOnly} + from '#composite/data'; import {withParsedCommentaryEntries} from '#composite/wiki-data'; export default templateCompositeFrom({ @@ -26,15 +28,23 @@ export default templateCompositeFrom({ withPropertyFromList({ list: '#parsedCommentaryEntries', - property: input.value('artist'), + property: input.value('artists'), }).outputs({ - '#parsedCommentaryEntries.artist': '#artists', + '#parsedCommentaryEntries.artists': '#artistLists', }), - { - dependencies: ['#artists'], - compute: ({'#artists': artists}) => - unique(artists.filter(artist => artist !== null)), - }, + withFlattenedList({ + list: '#artistLists', + }).outputs({ + '#flattenedList': '#artists', + }), + + withUniqueItemsOnly({ + list: '#artists', + }), + + exposeDependency({ + dependency: '#artists', + }), ], }); diff --git a/src/data/yaml.js b/src/data/yaml.js index 843e70b3..0734d539 100644 --- a/src/data/yaml.js +++ b/src/data/yaml.js @@ -21,6 +21,7 @@ import { decorateErrorWithIndex, decorateErrorWithAnnotation, empty, + filterAggregate, filterProperties, openAggregate, showAggregate, @@ -1686,8 +1687,10 @@ export function filterReferenceErrors(wikiData) { if (value) { value = Array.from(value.matchAll(commentaryRegex)) - .map(({groups}) => groups.artistReference); + .map(({groups}) => groups.artistReferences) + .map(text => text.split(',').map(text => text.trim())); } + writeProperty = false; break; } @@ -1804,11 +1807,22 @@ export function filterReferenceErrors(wikiData) { let newPropertyValue = value; - if (Array.isArray(value)) { + if (findFnKey === '_commentary') { + // Commentary doesn't write a property value, so no need to set. + filter( + value, {message: errorMessage}, + decorateErrorWithIndex(refs => + (refs.length === 1 + ? suppress(findFn)(refs[0]) + : filterAggregate( + refs, {message: `Errors in entry's artist references`}, + decorateErrorWithIndex(suppress(findFn))) + .aggregate + .close()))); + } else if (Array.isArray(value)) { newPropertyValue = filter( - value, - decorateErrorWithIndex(suppress(findFn)), - {message: errorMessage}); + value, {message: errorMessage}, + decorateErrorWithIndex(suppress(findFn))); } else { nest({message: errorMessage}, suppress(({call}) => { diff --git a/src/util/wiki-data.js b/src/util/wiki-data.js index 75a141d3..5e3182a9 100644 --- a/src/util/wiki-data.js +++ b/src/util/wiki-data.js @@ -641,8 +641,10 @@ export function sortFlashesChronologically(data, { // // * "25 December 2019" - one or two number digits, followed by any text, // followed by four number digits -// * "12/25/2019" - one or two number digits, a slash, one or two number -// digits, a slash, and two to four number digits +// * "December 25, 2019" - one all-letters word, a space, one or two number +// digits, a comma, and four number digits +// * "12/25/2019" etc - three sets of one to four number digits, separated +// by slashes or dashes (only valid orders are MM/DD/YYYY and YYYY/MM/DD) // // Capturing group "artistReference" is all the characters between <i> and </i> // (apart from the pipe and "artistDisplayText" text, if present), and is either @@ -652,7 +654,7 @@ export function sortFlashesChronologically(data, { // out of the original string based on the indices matched using this. // export const commentaryRegex = - /^<i>(?<artistReference>.+?)(?:\|(?<artistDisplayText>.+))?:<\/i>(?: \((?<annotation>(?:.*?(?=[,)]))*?)(?:,? ?(?<date>[a-zA-Z]+ [0-9]{1,2}, [0-9]{4,4}|[0-9]{1,2} [^,]*[0-9]{4,4}|[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4}))?\))?/gm; + /^<i>(?<artistReferences>.+?)(?:\|(?<artistDisplayText>.+))?:<\/i>(?: \((?<annotation>(?:.*?(?=,|\)$))*?)(?:,? ?(?<date>[a-zA-Z]+ [0-9]{1,2}, [0-9]{4,4}|[0-9]{1,2} [^,]*[0-9]{4,4}|[0-9]{1,4}[-/][0-9]{1,4}[-/][0-9]{1,4}))?\))?$/gm; export function filterAlbumsByCommentary(albums) { return albums |