diff options
-rw-r--r-- | src/common-util/wiki-data.js | 7 | ||||
-rw-r--r-- | src/content/dependencies/transformContent.js | 22 | ||||
-rw-r--r-- | src/data/checks.js | 10 | ||||
-rw-r--r-- | src/find.js | 93 |
4 files changed, 99 insertions, 33 deletions
diff --git a/src/common-util/wiki-data.js b/src/common-util/wiki-data.js index 0f6591c1..3fde2495 100644 --- a/src/common-util/wiki-data.js +++ b/src/common-util/wiki-data.js @@ -11,7 +11,7 @@ export {filterMultipleArrays} from './sugar.js'; // Generic value operations -export function getKebabCase(name) { +export function getCaseSensitiveKebabCase(name) { return name // Spaces to dashes @@ -53,9 +53,10 @@ export function getKebabCase(name) { // Trim dashes on boundaries .replace(/^-+|-+$/g, '') +} - // Always lowercase - .toLowerCase(); +export function getKebabCase(name) { + return getCaseSensitiveKebabCase(name).toLowerCase(); } // Specific data utilities diff --git a/src/content/dependencies/transformContent.js b/src/content/dependencies/transformContent.js index 06056ffc..3f738db2 100644 --- a/src/content/dependencies/transformContent.js +++ b/src/content/dependencies/transformContent.js @@ -79,7 +79,14 @@ export default { ], sprawl(wikiData, content) { - const find = bindFind(wikiData, {mode: 'quiet'}); + const find = + bindFind(wikiData, { + mode: 'quiet', + fuzz: { + capitalization: true, + kebab: true, + }, + }); const {result: parsedNodes, error} = parseContentNodes(content ?? '', {errorMode: 'return'}); @@ -162,9 +169,16 @@ export default { data.label = enteredLabel ?? - (transformName && data.thing.name - ? transformName(data.thing.name, node, content) - : null); + + (transformName && data.thing.name && + replacerKeyImplied && replacerValue === data.thing.name + + ? transformName(data.thing.name, node, content) + : null) ?? + + (replacerKeyImplied + ? replacerValue + : null); data.hash = enteredHash ?? null; diff --git a/src/data/checks.js b/src/data/checks.js index 3fcb6d3b..5eba593b 100644 --- a/src/data/checks.js +++ b/src/data/checks.js @@ -637,7 +637,15 @@ export function reportContentTextErrors(wikiData, { }], ]; - const boundFind = bindFind(wikiData, {mode: 'error'}); + const boundFind = + bindFind(wikiData, { + mode: 'error', + fuzz: { + capitalization: true, + kebab: true, + }, + }); + const findArtistOrAlias = bindFindArtistOrAlias(boundFind); function* processContent(input) { diff --git a/src/find.js b/src/find.js index 8f2170d4..b44c1bb2 100644 --- a/src/find.js +++ b/src/find.js @@ -4,6 +4,7 @@ import {colors, logWarn} from '#cli'; import {compareObjects, stitchArrays, typeAppearance} from '#sugar'; import thingConstructors from '#things'; import {isFunction, validateArrayItems} from '#validators'; +import {getCaseSensitiveKebabCase} from '#wiki-data'; import * as fr from './find-reverse.js'; @@ -30,7 +31,34 @@ function warnOrThrow(mode, message) { export const keyRefRegex = new RegExp(String.raw`^(?:(?<key>[a-z-]*):(?=\S))?(?<ref>.*)$`); -export function processAvailableMatchesByName(data, { +function getFuzzHash(fuzz = {}) { + if (!fuzz) { + return 0; + } + + return ( + fuzz.capitalization << 0 + + fuzz.kebab << 1 + ); +} + +export function fuzzName(name, fuzz = {}) { + if (!fuzz) { + return name; + } + + if (fuzz.capitalization) { + name = name.toLowerCase(); + } + + if (fuzz.kebab) { + name = getCaseSensitiveKebabCase(name); + } + + return name; +} + +export function processAvailableMatchesByName(data, fuzz, { include = _thing => true, getMatchableNames = thing => @@ -50,7 +78,7 @@ export function processAvailableMatchesByName(data, { continue; } - const normalizedName = name.toLowerCase(); + const normalizedName = fuzzName(name, fuzz); if (normalizedName in results) { if (normalizedName in multipleNameMatches) { @@ -97,9 +125,9 @@ export function processAvailableMatchesByDirectory(data, { return {results}; } -export function processAllAvailableMatches(data, spec) { +export function processAllAvailableMatches(data, fuzz, spec) { const {results: byName, multipleNameMatches} = - processAvailableMatchesByName(data, spec); + processAvailableMatchesByName(data, fuzz, spec); const {results: byDirectory} = processAvailableMatchesByDirectory(data, spec); @@ -150,19 +178,23 @@ function oopsNameCapitalizationMismatch(mode, { `Returning null for this reference.`); } -export function prepareMatchByName(mode, {byName, multipleNameMatches}) { +export function prepareMatchByName(mode, fuzz, {byName, multipleNameMatches}) { return (name) => { - const normalizedName = name.toLowerCase(); + const normalizedName = fuzzName(name, fuzz); const match = byName[normalizedName]; if (match) { - if (name === match.name) { - return match.thing; - } else { + if ( + !fuzz?.capitalization && + name !== match.name && + name.toLowerCase === match.name.toLowerCase() + ) { return oopsNameCapitalizationMismatch(mode, { matchingName: name, matchedName: match.name, }); + } else { + return match.thing; } } else if (multipleNameMatches[normalizedName]) { return oopsMultipleNameMatches(mode, { @@ -242,11 +274,18 @@ function findHelper({ // hasn't changed! const cache = new WeakMap(); - // The mode argument here may be 'warn', 'error', or 'quiet'. 'error' throws - // errors for null matches (with details about the error), while 'warn' and - // 'quiet' both return null, with 'warn' logging details directly to the - // console. - return (fullRef, data, {mode = 'warn'} = {}) => { + return (fullRef, data, { + // The mode argument here may be 'warn', 'error', or 'quiet'. 'error' throws + // errors for null matches (with details about the error), while 'warn' and + // 'quiet' both return null, with 'warn' logging details directly to the + // console. + mode = 'warn', + + fuzz = { + capitalization: false, + kebab: false, + }, + } = {}) => { if (!fullRef) return null; if (typeof fullRef !== 'string') { @@ -257,19 +296,23 @@ function findHelper({ throw new TypeError(`Expected data to be present`); } - let subcache = cache.get(data); - if (!subcache) { - subcache = - processAllAvailableMatches(data, { + let dataSubcache = cache.get(data); + if (!dataSubcache) { + cache.set(data, dataSubcache = new Map()); + } + + const fuzzHash = getFuzzHash(fuzz); + let fuzzSubcache = dataSubcache.get(fuzzHash); + if (!fuzzSubcache) { + dataSubcache.set(fuzzHash, fuzzSubcache = + processAllAvailableMatches(data, fuzz, { include, getMatchableNames, getMatchableDirectories, - }); - - cache.set(data, subcache); + })); } - const {byDirectory, byName, multipleNameMatches} = subcache; + const {byDirectory, byName, multipleNameMatches} = fuzzSubcache; return matchHelper(fullRef, mode, { matchByDirectory: @@ -279,7 +322,7 @@ function findHelper({ }), matchByName: - prepareMatchByName(mode, { + prepareMatchByName(mode, fuzz, { byName, multipleNameMatches, }), @@ -358,7 +401,7 @@ function findMixedHelper(config) { const multipleNameMatches = Object.create(null); for (const spec of specs) { - processAvailableMatchesByName(data, { + processAvailableMatchesByName(data, null, { ...spec, results: byName, @@ -401,7 +444,7 @@ function findMixedHelper(config) { }, matchByName: - prepareMatchByName(mode, { + prepareMatchByName(mode, null, { byName, multipleNameMatches, }), |