@natlibfi/marc-record-validators-melinda 12.0.7 → 12.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addMissingField041.js +6 -3
- package/dist/addMissingField041.js.map +2 -2
- package/dist/addMissingField336.js +7 -4
- package/dist/addMissingField336.js.map +2 -2
- package/dist/addMissingField337.js +6 -3
- package/dist/addMissingField337.js.map +2 -2
- package/dist/addMissingField338.js +8 -5
- package/dist/addMissingField338.js.map +2 -2
- package/dist/cyrillux-usemarcon-replacement.js +5 -2
- package/dist/cyrillux-usemarcon-replacement.js.map +2 -2
- package/dist/cyrillux.js +10 -7
- package/dist/cyrillux.js.map +2 -2
- package/dist/disambiguateSeriesStatements.js +2 -1
- package/dist/disambiguateSeriesStatements.js.map +2 -2
- package/dist/drop-terms.js +5 -4
- package/dist/drop-terms.js.map +2 -2
- package/dist/fix-33X.js +7 -4
- package/dist/fix-33X.js.map +2 -2
- package/dist/fix-country-codes.js +5 -0
- package/dist/fix-country-codes.js.map +2 -2
- package/dist/fix-language-codes.js +5 -1
- package/dist/fix-language-codes.js.map +2 -2
- package/dist/fix-sami-041.js +11 -10
- package/dist/fix-sami-041.js.map +2 -2
- package/dist/indicator-fixes.js +5 -1
- package/dist/indicator-fixes.js.map +2 -2
- package/dist/merge-fields/counterpartField.js +6 -6
- package/dist/merge-fields/counterpartField.js.map +2 -2
- package/dist/merge-fields/mergableIndicator.js +0 -3
- package/dist/merge-fields/mergableIndicator.js.map +2 -2
- package/dist/merge-fields/worldKnowledge.js.map +2 -2
- package/dist/mergeRelatorTermFields.js +9 -6
- package/dist/mergeRelatorTermFields.js.map +2 -2
- package/dist/normalize-dashes.js +7 -4
- package/dist/normalize-dashes.js.map +2 -2
- package/dist/normalize-identifiers.js.map +2 -2
- package/dist/normalize-utf8-diacritics.js.map +2 -2
- package/dist/normalizeFieldForComparison.js.map +1 -1
- package/dist/normalizeSubfieldValueForComparison.js.map +1 -1
- package/dist/punctuation2.js +5 -2
- package/dist/punctuation2.js.map +2 -2
- package/dist/reindexSubfield6OccurenceNumbers.js +11 -10
- package/dist/reindexSubfield6OccurenceNumbers.js.map +2 -2
- package/dist/removeDuplicateDataFields.js +3 -2
- package/dist/removeDuplicateDataFields.js.map +2 -2
- package/dist/removeInferiorDataFields.js.map +2 -2
- package/dist/resolveOrphanedSubfield6s.js +3 -2
- package/dist/resolveOrphanedSubfield6s.js.map +2 -2
- package/dist/sortSubfields.js +1 -1
- package/dist/sortSubfields.js.map +2 -2
- package/dist/stripPunctuation.js +4 -3
- package/dist/stripPunctuation.js.map +2 -2
- package/dist/subfield6Utils.js +4 -1
- package/dist/subfield6Utils.js.map +2 -2
- package/dist/subfield8Utils.js.map +2 -2
- package/dist/translate-terms.js +4 -3
- package/dist/translate-terms.js.map +2 -2
- package/dist/typeOfDate-008.js +3 -1
- package/dist/typeOfDate-008.js.map +2 -2
- package/dist/update-field-540.js.map +2 -2
- package/dist/urn.js +13 -12
- package/dist/urn.js.map +2 -2
- package/package.json +7 -7
- package/src/addMissingField041.js +8 -4
- package/src/addMissingField336.js +10 -5
- package/src/addMissingField337.js +9 -5
- package/src/addMissingField338.js +11 -6
- package/src/cyrillux-usemarcon-replacement.js +9 -5
- package/src/cyrillux.js +18 -12
- package/src/disambiguateSeriesStatements.js +4 -1
- package/src/drop-terms.js +8 -6
- package/src/fix-33X.js +10 -6
- package/src/fix-country-codes.js +7 -3
- package/src/fix-language-codes.js +8 -4
- package/src/fix-sami-041.js +13 -11
- package/src/indicator-fixes.js +10 -7
- package/src/merge-fields/counterpartField.js +10 -10
- package/src/merge-fields/mergableIndicator.js +3 -3
- package/src/merge-fields/worldKnowledge.js +11 -6
- package/src/mergeRelatorTermFields.js +12 -11
- package/src/normalize-dashes.js +11 -5
- package/src/normalize-identifiers.js +12 -19
- package/src/normalize-utf8-diacritics.js +6 -3
- package/src/normalizeFieldForComparison.js +2 -2
- package/src/normalizeSubfieldValueForComparison.js +2 -2
- package/src/punctuation2.js +34 -30
- package/src/reindexSubfield6OccurenceNumbers.js +13 -11
- package/src/removeDuplicateDataFields.js +29 -27
- package/src/removeInferiorDataFields.js +28 -24
- package/src/resolveOrphanedSubfield6s.js +6 -4
- package/src/sortSubfields.js +5 -5
- package/src/stripPunctuation.js +5 -3
- package/src/subfield6Utils.js +33 -35
- package/src/subfield8Utils.js +10 -7
- package/src/translate-terms.js +13 -9
- package/src/typeOfDate-008.js +4 -1
- package/src/update-field-540.js +7 -5
- package/src/urn.js +17 -13
- package/test-fixtures/drop-terms/02/metadata.json +1 -1
- package/test-fixtures/drop-terms/03/metadata.json +1 -1
- package/test-fixtures/drop-terms/04/metadata.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/merge-fields/counterpartField.js"],
|
|
4
|
-
"sourcesContent": ["// For each incoming field that\n\nimport createDebugLogger from 'debug';\nimport {fieldHasSubfield, fieldHasNSubfields, fieldHasMultipleSubfields, fieldToString, nvdebug, removeCopyright, tagIsRepeatable} from '../utils.js';\nimport {cloneAndNormalizeFieldForComparison, cloneAndRemovePunctuation} from '../normalizeFieldForComparison.js';\nimport {normalizeControlSubfieldValue} from '../normalize-identifiers.js';\n\nimport {getMergeConstraintsForTag} from './mergeConstraints.js';\nimport {controlSubfieldsPermitMerge} from './controlSubfields.js';\nimport {mergableIndicator1, mergableIndicator2} from './mergableIndicator.js';\nimport {partsAgree} from '../normalizeSubfieldValueForComparison.js';\nimport {getSynonym, normalizeForSamenessCheck, valueCarriesMeaning} from './worldKnowledge.js';\nimport {provenanceSubfieldsPermitMerge} from './dataProvenance.js';\n\n// NB! We are using internal prefix '(FIN11)' instead of global (FI-ASTERI-N) here. The latter would be better but would require some work and testing.\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeField:counterpart');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\n// NB! FIN11 $0 pairing is handled in this code. We might want to support others, esp. FIN13 as well.\n\nconst counterpartRegexps = { // NB! tag is from source!\n // Note that in the normal case, all source 1XX fields have been converted to 7XX fields.\n '100': /^[17]00$/u, '110': /^[17]10$/u, '111': /^[17]11$/u, '130': /^[17]30$/u,\n '260': /^26[04]$/u, '264': /^26[04]$/u,\n '700': /^[17]00$/u, '710': /^[17]10$/u, '711': /^[17]11$/u, '730': /^[17]30$/u,\n // Hacks:\n '940': /^[29]40$/u, '973': /^[79]73$/u\n};\n\nconst counterpartRegexpsSingle = {\n // when base===source, never merge 1XX to 7XX, always 7XX to 1XX! Also, don't merge 264 to 260.\n '260': /^26[04]$/u,\n '700': /^[17]00$/u, '110': /^[17]10$/u, '111': /^[17]11$/u, '130': /^[17]30$/u,\n // Hacks:\n '940': /^[29]40$/u, '973': /^[79]73$/u\n};\n\n\nexport function splitToNameAndQualifier(value) {\n if (value.match(/^.* \\([^()]+\\)$/u)) {\n const name = value.replace(/^(.*) \\([^()]+\\)$/u, '$1');\n const qualifier = value.replace(/^.* (\\([^()]+\\))$/u, '$1');\n return [name, qualifier];\n }\n return [value, undefined];\n}\n\nfunction splitToNameAndQualifierAndProcessName(name) {\n //const nameOnly = name.replace(/(?: \\([^)]+\\)| abp?| Kustannus| Kustannus Oy|, kustannusosakeyhti\u00F6| oyj?| ry)$/ugi, '');\n const [qualifierlessName, qualifier] = splitToNameAndQualifier(name);\n\n const [prefix, basename, suffix] = stripPrefixAndSuffix(qualifierlessName);\n\n return {name: getBestName(basename).toLowerCase(), prefix, suffix, qualifier};\n\n function stripPrefixAndSuffix(companyName) {\n const [nameOnly, suffix] = extractSuffix(companyName);\n const [nameOnly2, prefix] = extractPrefix(nameOnly);\n return [prefix, nameOnly2, suffix];\n }\n\n function extractSuffix(name) {\n const nameOnly = name.replace(/(?: \\([^)]+\\)| abp?| Kustannus| Kustannus Oy|, kustannusosakeyhti\u00F6| oyj?| ry)$/ugi, '');\n if (nameOnly === name) {\n return [name, undefined];\n }\n return [nameOnly, name.substring(nameOnly.length).replace(/^,? /u, '')];\n }\n\n function extractPrefix(name) {\n const nameOnly = name.replace(/^(?:Ab|Kustannusosakeyhti\u00F6|Kustannus Oy|Oy) /ugi, '');\n if (nameOnly === name) {\n return [name, undefined];\n }\n return [nameOnly, name.substring(0, name.length - nameOnly.length - 1)]; // -1 removes final space\n }\n\n function getBestName(name) {\n const NAME = name.toUpperCase();\n\n if (NAME === 'WSOY') {\n return 'Werner S\u00F6derstr\u00F6m osakeyhti\u00F6';\n }\n if (NAME === 'NTAMO') {\n return 'ntamo';\n }\n return name;\n }\n}\n\nexport function canContainOptionalQualifier(tag, subfieldCode) {\n // We have made 300$a NON-repeatable (against specs), as we never want them to be repeated (probably near-duplicates)\n if (tag === '300' && subfieldCode === 'a') {\n return true;\n }\n // 776$i is actually not needed for counterpart stuff (since it's repeatable), but it is needed in merge subfield stage.\n if (tag === '776' && subfieldCode === 'i') {\n return true;\n }\n return false;\n}\n\nfunction withAndWithoutQualifierAgree(value1, value2, tag, subfieldCode) {\n // Split value to name and qualifier parts. Names must be equal, and qualifiers must be equal, iff both values contain them.\n if (!canContainOptionalQualifier(tag, subfieldCode)) {\n return false;\n }\n\n const [name1, qualifier1] = splitToNameAndQualifier(value1);\n const [name2, qualifier2] = splitToNameAndQualifier(value2);\n\n //nvdebug(`CN1: '${name1}', '${qualifier1}'`, debugDev);\n //nvdebug(`CN2: '${name2}', '${qualifier2}'`, debugDev);\n\n if (name1.toLowerCase() !== name2.toLowerCase()) {\n return false;\n }\n\n // If either value does not have a qualifier, they are considered equals:\n if (qualifier1 === undefined || qualifier2 === undefined || qualifier1.toLowerCase() === qualifier2.toLowerCase()) {\n return true;\n }\n\n return false;\n}\n\nfunction corporateNamesAgree(value1, value2, tag, subfieldCode) {\n if (subfieldCode !== 'a' || !['110', '610', '710', '810'].includes(tag)) {\n return false;\n }\n const nameData1 = splitToNameAndQualifierAndProcessName(value1);\n const nameData2 = splitToNameAndQualifierAndProcessName(value2);\n\n nvdebug(`CN1: '${nameData1.name}', '${nameData1.qualifier}'`, debugDev);\n nvdebug(`CN2: '${nameData2.name}', '${nameData2.qualifier}'`, debugDev);\n\n if (nameData1.name !== nameData2.name) {\n return false;\n }\n\n if (nameData1.qualifier && nameData2.qualifier && nameData1.qualifier !== nameData2.qualifier) {\n return false;\n }\n // Currently all prefixes and suffixes are publisher information, so there's no point comparing them any further...\n\n return true;\n}\n\nfunction counterpartExtraNormalize(tag, subfieldCode, value) {\n // Remove trailing punctuation:\n value = value.replace(/(\\S)(?:,|\\.|\\?|!|\\. -| *:| *;| =| \\/)$/u, '$1');\n // Remove brackets:\n value = value.replace(/^\\(([^()]+)\\)$/u, '$1'); // Remove initial '(' and final ')' if both exist.\n value = value.replace(/^\\[([^[\\]]+)\\]$/u, '$1'); // Remove initial '[' and final ']' if both exist.\n // Mainly for field 260$c:\n if (tag === '260' && subfieldCode === 'c') {\n value = removeCopyright(value);\n }\n value = value.replace(/http:\\/\\//ug, 'https://'); // MET-501: http vs https\n value = getSynonym(tag, subfieldCode, value);\n value = normalizeForSamenessCheck(tag, subfieldCode, value); // Better to remove trailing punctuation before calling this...\n\n\n return value;\n}\n\nfunction hasCommonNominator(field1, field2, subfieldCode) {\n //nvdebug(`hasCommonNominator(${subfieldCode})? '${fieldToString(originalBaseField)}' vs '${fieldToString(originalSourceField)}'`, debugDev);\n\n // If base has $a and source has $b, there's no common nominator, thus fail...\n const subfields1 = field1.subfields.filter(subfield => subfield.code === subfieldCode && valueCarriesMeaning(field1.tag, subfield.code, subfield.value));\n const subfields2 = field2.subfields.filter(subfield => subfield.code === subfieldCode && valueCarriesMeaning(field2.tag, subfield.code, subfield.value));\n\n return subfields1.length > 0 && subfields2.length > 0;\n}\n\nfunction tagToRegexp(tag, internalMerge = false) {\n if (internalMerge && tag in counterpartRegexpsSingle) {\n return counterpartRegexpsSingle[tag];\n }\n if (!internalMerge && tag in counterpartRegexps) { // eg. 700 looks for tag /^[17]00$/...\n const regexp = counterpartRegexps[tag];\n //nvdebug(`regexp for ${tag} found: ${regexp}`, debugDev);\n return regexp;\n }\n //nvdebug(`WARNING: tagToRegexp(${tag}): no precompiled regexp found.`, debugDev);\n return new RegExp(`^${tag}$`, 'u');\n}\n\nfunction areRequiredSubfieldsPresent(field) {\n const subfieldString = getMergeConstraintsForTag(field.tag, 'required').join('');\n if (subfieldString === null) {\n return true;\n } // nothing is required\n const subfieldArray = subfieldString.split('');\n return subfieldArray.every(sfcode => {\n const result = fieldHasSubfield(field, sfcode);\n if (!result) {\n debugDev(`Required subfield \u2021${sfcode} not found in '${fieldToString(field)}'!`);\n return false;\n }\n return true;\n });\n}\n\nfunction getUnbalancedPairedSubfieldCode(field1, field2) {\n const fullSubfieldString = getMergeConstraintsForTag(field1.tag, 'paired').join('') || '';\n\n if (fullSubfieldString === '') {\n return false;\n }\n\n // If the two fields share the FIN11 ID (WE SHOULD SUPPORT FIN13 AS WELL) there's no need to check the 'paired' constraint regarding related subfields.\n // Meaning that it this is FIN11 match we should not bother checking whether something like 100$b/c/d/q is there. (NB! Note that 'required' check is not alleviated in this way)\n // (I'm not saying that 100$b/c/d/q are in 'paired' contraint, I'm just illustrating the issue here)\n const pairable = pairableIdentifier(field1, field2, '(FIN11)');\n const subfieldString = pairable ? removeNameRelatedSubfieldCodes(fullSubfieldString, field1.tag) : fullSubfieldString;\n debug(`CHECK ${pairable ? 'PAIRABLE ' : ''}${field1.tag} PAIRS: '${fullSubfieldString}' => '${subfieldString}'`);\n\n if (subfieldString === '') {\n return false;\n }\n const subfieldArray = subfieldString.split('');\n\n return subfieldArray.find(sfcode => fieldHasNSubfields(field1, sfcode) !== fieldHasNSubfields(field2, sfcode));\n}\n\nfunction syntacticallyMergablePair(baseField, sourceField, config) {\n // Indicators must typically be equal (there are exceptions such as non-filing characters though):\n nvdebug(\"CHECK SYNTAX\");\n if (!mergableIndicator1(baseField, sourceField, config)) {\n nvdebug(`non-mergable (reason: indicator1): ${JSON.stringify(config)}`, debugDev);\n return false;\n }\n\n if (!mergableIndicator2(baseField, sourceField, config)) {\n nvdebug(`non-mergable (reason: indicator2): ${JSON.stringify(config)}`, debugDev);\n return false;\n }\n\n if (!controlSubfieldsPermitMerge(baseField, sourceField)) {\n nvdebug('non-mergable (reason: control subfield)', debugDev);\n return false;\n }\n\n if (!provenanceSubfieldsPermitMerge(baseField, sourceField)) {\n nvdebug('non-mergable (reason: data provenance subfield)', debugDev);\n return false;\n }\n\n // NB! field1.tag and field2.tag might differ (1XX vs 7XX). Therefore required subfields might theoretically differ as well.\n // Note: Theoretically 260 $efg vs 264 with IND2=3 has already been handled by the preprocessor.\n // Thus check both:\n if (!areRequiredSubfieldsPresent(baseField) || !areRequiredSubfieldsPresent(sourceField)) {\n nvdebug('non-mergable (reason: missing subfields)', debugDev);\n return false;\n }\n\n // Stuff of Hacks! Eg. require that both fields either have or have not X00$t:\n const subfieldCodeThatFailsToPair = getUnbalancedPairedSubfieldCode(baseField, sourceField);\n if (subfieldCodeThatFailsToPair) {\n nvdebug(`non-mergable (reason: required subfield pair check failed for code: '${subfieldCodeThatFailsToPair}')`, debugDev);\n return false;\n }\n\n return true;\n}\n\nfunction mergablePair(baseField, sourceField, config) {\n if (!syntacticallyMergablePair(baseField, sourceField, config)) {\n nvdebug('non-mergable (reason: syntax)', debugDev);\n return false;\n }\n\n //debug('Test semantics...');\n if (!semanticallyMergablePair(baseField, sourceField)) {\n nvdebug('non-mergable (reason: semantics)', debugDev);\n return false;\n }\n\n nvdebug(`MERGABLE PAIR:\\n B: ${fieldToString(baseField)}\\n S: ${fieldToString(sourceField)}`, debugDev);\n return true;\n}\n\nfunction removeNameRelatedSubfieldCodes(codestring, tag) {\n // If we have $0 (FIN11) match, we are not interested in the core name subfields. Remove them from the subfield codes string.\n const removables = getNameRelatedSubfieldCodes(tag); // These are different for X00, X10 and X11...\n return removeCharsFromString(codestring, removables);\n\n function removeCharsFromString(string, removableCharsAsString) {\n const removableChars = removableCharsAsString.split('');\n return string.split('').filter(c => !removableChars.includes(c)).join('');\n }\n\n function getNameRelatedSubfieldCodes(tag) {\n if (['100', '600', '700', '800'].includes(tag)) {\n return 'abcdq';\n }\n if (['110', '610', '710', '810'].includes(tag)) {\n return 'abcdn';\n }\n if (['111', '611', '711', '811'].includes(tag)) {\n return 'acden';\n }\n return '';\n }\n}\n\nfunction pairableIdentifier(field1, field2, prefix) {\n const normalizedPrefix = prefix;\n nvdebug(`PREF '${prefix}' => '${normalizedPrefix}'`);\n\n const prefixLength = normalizedPrefix.length;\n const identifiers1 = getIdentifiers(field1);\n if (identifiers1.length !== 1) {\n return false;\n }\n const identifiers2 = getIdentifiers(field2);\n if (identifiers2.length !== 1) {\n return false;\n }\n\n return identifiers1[0] === identifiers2[0];\n\n function getIdentifiers(field) {\n return field.subfields.filter(sf => sf.code === '0')\n .map(sf => normalizeControlSubfieldValue(sf.value))\n .filter(val => val.substring(0, prefixLength) === normalizedPrefix);\n }\n}\n\n\nfunction hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field) {\n // 700$s?\n if (field.tag === '260' || field.tag === '264') {\n return ['a', 'b', 'c', 'e', 'f', 'g'].some(subfieldCode => fieldHasMultipleSubfields(field, subfieldCode));\n }\n if (field.tag === '382') {\n return ['a', 'b', 'd', 'e', 'n', 'p'].some(subfieldCode => fieldHasMultipleSubfields(field, subfieldCode));\n }\n if (field.tag === '505') {\n return ['t', 'r', 'g'].some(subfieldCode => fieldHasMultipleSubfields(field, subfieldCode));\n }\n\n return false;\n}\n\nfunction getRelevantSubfieldValues(field, subfieldCode) {\n const values = field.subfields.filter(sf => sf.code === subfieldCode).map(sf => counterpartExtraNormalize(field.tag, subfieldCode, sf.value));\n\n return values.filter(v => valueCarriesMeaning(field.tag, subfieldCode, v));\n}\n\nfunction pairableValue(tag, subfieldCode, value1, value2) {\n if (value1 === value2) {\n return true;\n }\n\n // This function could just return true or false.\n // I thought of preference when I wrote this, but preference implemented *here* (modularity). mergeFields.js should handle preference.\n if (withAndWithoutQualifierAgree(value1, value2, tag, subfieldCode)) {\n // 300$a \"whatever\" and \"whatever (123 sivua)\"\n return true;\n }\n if (partsAgree(value1, value2, tag, subfieldCode) || corporateNamesAgree(value1, value2, tag, subfieldCode)) {\n // Pure baseness: here we assume that base's value1 is better than source's value2.\n return true;\n }\n\n return false;\n}\n\nfunction pairableValueInArray(tag, subfieldCode, val, arr) {\n return arr.some(val2 => pairableValue(tag, subfieldCode, val, val2));\n}\n\n\nfunction tightSubfieldMatch(field1, field2, subfieldCode, mustHave = false) {\n nvdebug(`${subfieldCode} F1: ${fieldToString(field1)}`);\n nvdebug(`${subfieldCode} F2: ${fieldToString(field2)}`);\n const values1 = getRelevantSubfieldValues(field1, subfieldCode);\n const values2 = getRelevantSubfieldValues(field2, subfieldCode);\n\n if(!mustHave) {\n if (values1.length === 0 || values2.length === 0) {\n return true;\n }\n }\n\n if (values1.length !== values2.length) {\n return false;\n }\n\n nvdebug(`Compare $${subfieldCode} contents:\\n '${values1.join(\"'\\n '\")}' vs\\n '${values2.join(\"'\\n '\")}'`);\n return values1.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values2)) && values2.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values1));\n}\n\nfunction looseSubfieldMatch(field1, field2, subfieldCode) {\n const values1 = getRelevantSubfieldValues(field1, subfieldCode);\n const values2 = getRelevantSubfieldValues(field2, subfieldCode);\n if (values1.length === 0 || values2.length === 0) {\n return true;\n }\n // Subsets are fine:\n if (values1.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values2))) {\n return true;\n }\n if (values2.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values1))) {\n return true;\n }\n return false;\n}\n\nfunction semanticallyMergablePair(baseField, sourceField) {\n const field1 = cloneAndNormalizeFieldForComparison(baseField);\n const field2 = cloneAndNormalizeFieldForComparison(sourceField);\n\n const string1 = fieldToString(field1);\n const string2 = fieldToString(field2);\n\n nvdebug(`IN ${baseField.tag}: pairableName():\\n '${string1}' vs\\n '${string2}'`, debugDev);\n if (string1 === string2) {\n return true;\n }\n\n const mergeConstraints = getMergeConstraintsForTag(field1.tag); // The tag doe\n if (mergeConstraints.length === 0) { // We have no constraints defined for this tag -> fail\n return false;\n }\n\n // Essentially these are too hard to handle with field-merge (eg. multi-505$g)\n if (hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field1) || hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field2)) {\n nvdebug(`Unmergable: data is too complex to be automatically safely merged`, debugDev);\n return false;\n }\n\n const asteriMatch = pairableIdentifier(field1, field2, '(FIN11)'); // If there's a match, there's no need to check the name (Caretaker will handle these.)\n // WE COULD REMOVE THESE FIELDS IN MERGE, SO THAT WE WON'T GET FUNNY NAMES).\n\n // NB! Currently we should get only one mergeContraint. However, should we support multiple merge contraints (= multiple profiles)?\n const allRequired = mergeConstraints[0].required || ''; // getMergeConstraintsForTag(field1.tag, 'required') || '';\n const reallyRequired = asteriMatch ? removeNameRelatedSubfieldCodes(allRequired, field1.tag) : allRequired;\n\n //nvdebug(`WP1: '${allRequired}' => ${reallyRequired}`);\n if (!reallyRequired.split('').every(c => tightSubfieldMatch(field1, field2, c, true))) {\n return false;\n }\n\n const allPaired = mergeConstraints[0].paired || ''; // getMergeConstraintsForTag(field1.tag, 'paired') || '';\n const reallyPaired = asteriMatch ? removeNameRelatedSubfieldCodes(allPaired, field1.tag) : allPaired;\n //nvdebug(`WP2: '${allPaired}' => ${reallyPaired}`);\n if (!reallyPaired.split('').every(c => tightSubfieldMatch(field1, field2, c, false))) {\n return false;\n }\n\n const allKeys = mergeConstraints[0].key || ''; // getMergeConstraintsForTag(field1.tag, 'key') || '';\n const relevantKeys = asteriMatch ? removeNameRelatedSubfieldCodes(allKeys, field1.tag) : allKeys\n //nvdebug(`WP3: keys='${allKeys}' => ${relevantKeys}`);\n if (!relevantKeys.split('').every(c => looseSubfieldMatch(field1, field2, c))) {\n return false;\n }\n //nvdebug('WP4');\n\n // required/paired/keys checks did not fail. Now check that did they really succeed\n if (allRequired.length > 0) { // I think we should use all here\n return true;\n }\n\n if (reallyPaired.length > 0 && field1.subfields.some(sf => reallyPaired.includes(sf.code))) {\n return true;\n }\n\n if(!tagIsRepeatable(field1.tag) || relevantKeys.length == 0) {\n return true;\n }\n\n // Raison d'\u00EAtre is long forgotten, but my educated guess about this: if 'key' is defined in merge constraints\n // for this field, then at least one of the subfield codes in 'key' must be present in both fields.\n // However, this is not necessarily right.\n if (relevantKeys.length > 0) {\n if (field1.subfields.some(sf => relevantKeys.includes(sf.code)) || field2.subfields.some(sf => relevantKeys.includes(sf.code))) { \n return relevantKeys.split('').some(code => hasCommonNominator(field1, field2, code));\n }\n }\n\n nvdebug(` name mismatch (${keys}):`, debugDev);\n nvdebug(` '${fieldToString(baseField)}' vs`, debugDev);\n nvdebug(` '${fieldToString(sourceField)}'`, debugDev);\n return false;\n}\n\nfunction getAlternativeNamesFrom9XX(record, field) {\n // Should we support 6XX and 8XX as well? Prolly not...\n if (!field.tag.match(/^(?:100|110|111|600|610|611|700|710|711)$/u)) {\n return [];\n }\n const tag = `9${field.tag.substring(1)}`;\n const cands = record.get(tag).filter(f => fieldHasSubfield(f, 'a') && fieldHasSubfield(f, 'y'));\n if (cands.length === 0) {\n return [];\n }\n const punctuationlessField = cloneAndRemovePunctuation(field);\n const [name] = punctuationlessField.subfields.filter(sf => sf.code === 'a').map(sf => sf.value);\n\n return cands.map(candField => getAltName(candField)).filter(val => val !== undefined);\n\n\n function getAltName(altField) {\n const [altA] = altField.subfields.filter(sf => sf.code === 'a').map(sf => sf.value);\n const [altY] = altField.subfields.filter(sf => sf.code === 'y').map(sf => sf.value);\n nvdebug(`Compare '${name}' vs '${altA}'/'${altY}'`, debugDev);\n if (name === altA) {\n return altY;\n }\n if (name === altY) {\n return altA;\n }\n nvdebug(` miss`, debugDev);\n return undefined;\n }\n\n}\n\n\nfunction mergablePairWithAltName(normCandField, normalizedField, altName, config) {\n // Replace source field $a name with alternative name and then compare:\n const [a] = normalizedField.subfields.filter(sf => sf.code === 'a');\n if (!a) {\n return false;\n }\n a.value = altName;\n\n return mergablePair(normCandField, normalizedField, config);\n}\n\nfunction getCounterpartIndex(field, counterpartCands, altNames, config) {\n const normalizedField = cloneAndNormalizeFieldForComparison(field);\n const normalizedCounterpartCands = counterpartCands.map(f => cloneAndNormalizeFieldForComparison(f));\n const index = normalizedCounterpartCands.findIndex(normCandField => mergablePair(normCandField, normalizedField, config));\n if (index > -1) {\n return index;\n }\n\n return normalizedCounterpartCands.findIndex(normCandField => altNames.some(altName => mergablePairWithAltName(normCandField, normalizedField, altName, config)));\n}\n\n\nfunction field264Exception(baseField, sourceRecord, sourceField, config) {\n if (baseField.tag !== '264') {\n return false;\n }\n\n if (sourceField.tag !== '264' || sourceRecord.get('264').length !== 1) {\n return false;\n }\n\n // Don't worry about semantics:\n return syntacticallyMergablePair(sourceField, baseField, config);\n}\n\nfunction getCounterpartCandidates(field, record) {\n const counterpartCands = record.get(tagToRegexp(field.tag, record.internalMerge));\n\n // MELKEHITYS-2969: copyright years should not merge with non-copyright years\n if (field.tag === '260' && isNotCopyrightYear(field)) {\n return counterpartCands.filter(candField => !isCopyrightField264(candField));\n }\n\n if (field.tag === '264' && isCopyrightField264(field)) { // Copyright year\n return counterpartCands.filter(candField => !isNotCopyrightYear(candField));\n }\n\n function isCopyrightField264(field) {\n return field.tag === '264' && field.ind2 === '4';\n }\n\n function isNotCopyrightYear(field) {\n if (field.tag === '264') {\n return !isCopyrightField264(field);\n }\n // Field 260: copyright year does not contain $a or $b:\n return !field.subfields.some(sf => sf.code === 'a' && sf.code === 'b');\n }\n\n return counterpartCands;\n\n}\n\nexport function baseIsSource(base, source) {\n base.localTest = true;\n const result = source.localTest;\n delete base.localTest;\n return result;\n}\n\nexport function getCounterpart(baseRecord, sourceRecord, field, config) {\n // First get relevant candidate fields. Note that 1XX and corresponding 7XX are considered equal, and tags 260 and 264 are lumped together.\n // (<= Note that self-merge behaves differently from two records here.)\n // Hacks: 973 can merge with 773, 940 can merge with 240 (but not the other way around)\n //nvdebug(`COUNTERPART FOR '${fieldToString(field)}'?`, debugDev);\n const counterpartCands = getCounterpartCandidates(field, baseRecord).filter(f => !f.mergeCandidate);\n\n if (!counterpartCands || counterpartCands.length === 0) {\n //nvdebug(`No counterpart(s) found for ${fieldToString(field)}`, debugDev);\n return null;\n }\n\n nvdebug(`Compare incoming '${fieldToString(field)}' with (up to) ${counterpartCands.length} existing field(s)`, debugDev);\n\n const normalizedField = cloneAndNormalizeFieldForComparison(field); // mainly strip punctuation here\n\n nvdebug(` Normalize incoming field to: '${fieldToString(normalizedField)}'`, debugDev);\n\n const uniqueAlternativeNames = getUniqueAlernativeNames();\n\n //nvdebug(` S: ${fieldToString(normalizedField)}`, debugDev);\n // Then find (the index of) the first mathing candidate field and return it.\n const index = getCounterpartIndex(normalizedField, counterpartCands, uniqueAlternativeNames, config);\n\n if (index > -1) {\n return counterpartCands[index];\n }\n\n // MET-456 exception\n if (counterpartCands.length === 1 && field264Exception(counterpartCands[0], sourceRecord, field, config)) {\n return counterpartCands[0];\n }\n\n return null;\n\n function getUniqueAlernativeNames() {\n if (baseIsSource(baseRecord, sourceRecord)) {\n return [];\n }\n // Try to look for alternative names from base and source record's 9XX fields:\n const alternativeNames = getAlternativeNamesFrom9XX(baseRecord, field).concat(getAlternativeNamesFrom9XX(sourceRecord, field));\n return alternativeNames.filter((name, i) => alternativeNames.indexOf(name) === i);\n }\n}\n\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["// For each incoming field that\n\nimport createDebugLogger from 'debug';\nimport {fieldHasSubfield, fieldHasNSubfields, fieldHasMultipleSubfields, fieldToString, nvdebug, removeCopyright, tagIsRepeatable} from '../utils.js';\nimport {cloneAndNormalizeFieldForComparison, cloneAndRemovePunctuation} from '../normalizeFieldForComparison.js';\nimport {normalizeControlSubfieldValue} from '../normalize-identifiers.js';\n\nimport {getMergeConstraintsForTag} from './mergeConstraints.js';\nimport {controlSubfieldsPermitMerge} from './controlSubfields.js';\nimport {mergableIndicator1, mergableIndicator2} from './mergableIndicator.js';\nimport {partsAgree} from '../normalizeSubfieldValueForComparison.js';\nimport {getSynonym, normalizeForSamenessCheck, valueCarriesMeaning} from './worldKnowledge.js';\nimport {provenanceSubfieldsPermitMerge} from './dataProvenance.js';\n\n// NB! We are using internal prefix '(FIN11)' instead of global (FI-ASTERI-N) here. The latter would be better but would require some work and testing.\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeField:counterpart');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\n// NB! FIN11 $0 pairing is handled in this code. We might want to support others, esp. FIN13 as well.\n\nconst counterpartRegexps = { // NB! tag is from source!\n // Note that in the normal case, all source 1XX fields have been converted to 7XX fields.\n '100': /^[17]00$/u, '110': /^[17]10$/u, '111': /^[17]11$/u, '130': /^[17]30$/u,\n '260': /^26[04]$/u, '264': /^26[04]$/u,\n '700': /^[17]00$/u, '710': /^[17]10$/u, '711': /^[17]11$/u, '730': /^[17]30$/u,\n // Hacks:\n '940': /^[29]40$/u, '973': /^[79]73$/u\n};\n\nconst counterpartRegexpsSingle = {\n // when base===source, never merge 1XX to 7XX, always 7XX to 1XX! Also, don't merge 264 to 260.\n '260': /^26[04]$/u,\n '700': /^[17]00$/u, '110': /^[17]10$/u, '111': /^[17]11$/u, '130': /^[17]30$/u,\n // Hacks:\n '940': /^[29]40$/u, '973': /^[79]73$/u\n};\n\n\nexport function splitToNameAndQualifier(value) {\n if (value.match(/^.* \\([^()]+\\)$/u)) {\n const name = value.replace(/^(.*) \\([^()]+\\)$/u, '$1');\n const qualifier = value.replace(/^.* (\\([^()]+\\))$/u, '$1');\n return [name, qualifier];\n }\n return [value, undefined];\n}\n\nfunction splitToNameAndQualifierAndProcessName(name) {\n //const nameOnly = name.replace(/(?: \\([^)]+\\)| abp?| Kustannus| Kustannus Oy|, kustannusosakeyhti\u00F6| oyj?| ry)$/ugi, '');\n const [qualifierlessName, qualifier] = splitToNameAndQualifier(name);\n\n const [prefix, basename, suffix] = stripPrefixAndSuffix(qualifierlessName);\n\n return {name: getBestName(basename).toLowerCase(), prefix, suffix, qualifier};\n\n function stripPrefixAndSuffix(companyName) {\n const [nameOnly, suffix] = extractSuffix(companyName);\n const [nameOnly2, prefix] = extractPrefix(nameOnly);\n return [prefix, nameOnly2, suffix];\n }\n\n function extractSuffix(name) {\n const nameOnly = name.replace(/(?: \\([^)]+\\)| abp?| Kustannus| Kustannus Oy|, kustannusosakeyhti\u00F6| oyj?| ry)$/ugi, '');\n if (nameOnly === name) {\n return [name, undefined];\n }\n return [nameOnly, name.substring(nameOnly.length).replace(/^,? /u, '')];\n }\n\n function extractPrefix(name) {\n const nameOnly = name.replace(/^(?:Ab|Kustannusosakeyhti\u00F6|Kustannus Oy|Oy) /ugi, '');\n if (nameOnly === name) {\n return [name, undefined];\n }\n return [nameOnly, name.substring(0, name.length - nameOnly.length - 1)]; // -1 removes final space\n }\n\n function getBestName(name) {\n const NAME = name.toUpperCase();\n\n if (NAME === 'WSOY') {\n return 'Werner S\u00F6derstr\u00F6m osakeyhti\u00F6';\n }\n if (NAME === 'NTAMO') {\n return 'ntamo';\n }\n return name;\n }\n}\n\nexport function canContainOptionalQualifier(tag, subfieldCode) {\n // We have made 300$a NON-repeatable (against specs), as we never want them to be repeated (probably near-duplicates)\n if (tag === '300' && subfieldCode === 'a') {\n return true;\n }\n // 776$i is actually not needed for counterpart stuff (since it's repeatable), but it is needed in merge subfield stage.\n if (tag === '776' && subfieldCode === 'i') {\n return true;\n }\n return false;\n}\n\nfunction withAndWithoutQualifierAgree(value1, value2, tag, subfieldCode) {\n // Split value to name and qualifier parts. Names must be equal, and qualifiers must be equal, iff both values contain them.\n if (!canContainOptionalQualifier(tag, subfieldCode)) {\n return false;\n }\n\n const [name1, qualifier1] = splitToNameAndQualifier(value1);\n const [name2, qualifier2] = splitToNameAndQualifier(value2);\n\n //nvdebug(`CN1: '${name1}', '${qualifier1}'`, debugDev);\n //nvdebug(`CN2: '${name2}', '${qualifier2}'`, debugDev);\n\n if (name1.toLowerCase() !== name2.toLowerCase()) {\n return false;\n }\n\n // If either value does not have a qualifier, they are considered equals:\n if (qualifier1 === undefined || qualifier2 === undefined || qualifier1.toLowerCase() === qualifier2.toLowerCase()) {\n return true;\n }\n\n return false;\n}\n\nfunction corporateNamesAgree(value1, value2, tag, subfieldCode) {\n if (subfieldCode !== 'a' || !['110', '610', '710', '810'].includes(tag)) {\n return false;\n }\n const nameData1 = splitToNameAndQualifierAndProcessName(value1);\n const nameData2 = splitToNameAndQualifierAndProcessName(value2);\n\n nvdebug(`CN1: '${nameData1.name}', '${nameData1.qualifier}'`, debugDev);\n nvdebug(`CN2: '${nameData2.name}', '${nameData2.qualifier}'`, debugDev);\n\n if (nameData1.name !== nameData2.name) {\n return false;\n }\n\n if (nameData1.qualifier && nameData2.qualifier && nameData1.qualifier !== nameData2.qualifier) {\n return false;\n }\n // Currently all prefixes and suffixes are publisher information, so there's no point comparing them any further...\n\n return true;\n}\n\nfunction counterpartExtraNormalize(tag, subfieldCode, value) {\n // Remove trailing punctuation:\n value = value.replace(/(\\S)(?:,|\\.|\\?|!|\\. -| *:| *;| =| \\/)$/u, '$1');\n // Remove brackets:\n value = value.replace(/^\\(([^()]+)\\)$/u, '$1'); // Remove initial '(' and final ')' if both exist.\n value = value.replace(/^\\[([^[\\]]+)\\]$/u, '$1'); // Remove initial '[' and final ']' if both exist.\n // Mainly for field 260$c:\n if (tag === '260' && subfieldCode === 'c') {\n value = removeCopyright(value);\n }\n value = value.replace(/http:\\/\\//ug, 'https://'); // MET-501: http vs https\n value = getSynonym(tag, subfieldCode, value);\n value = normalizeForSamenessCheck(tag, subfieldCode, value); // Better to remove trailing punctuation before calling this...\n\n\n return value;\n}\n\nfunction hasCommonNominator(field1, field2, subfieldCode) {\n //nvdebug(`hasCommonNominator(${subfieldCode})? '${fieldToString(originalBaseField)}' vs '${fieldToString(originalSourceField)}'`, debugDev);\n\n // If base has $a and source has $b, there's no common nominator, thus fail...\n const subfields1 = field1.subfields.filter(subfield => subfield.code === subfieldCode && valueCarriesMeaning(field1.tag, subfield.code, subfield.value));\n const subfields2 = field2.subfields.filter(subfield => subfield.code === subfieldCode && valueCarriesMeaning(field2.tag, subfield.code, subfield.value));\n\n return subfields1.length > 0 && subfields2.length > 0;\n}\n\nfunction tagToRegexp(tag, internalMerge = false) {\n if (internalMerge && tag in counterpartRegexpsSingle) {\n return counterpartRegexpsSingle[tag];\n }\n if (!internalMerge && tag in counterpartRegexps) { // eg. 700 looks for tag /^[17]00$/...\n const regexp = counterpartRegexps[tag];\n //nvdebug(`regexp for ${tag} found: ${regexp}`, debugDev);\n return regexp;\n }\n //nvdebug(`WARNING: tagToRegexp(${tag}): no precompiled regexp found.`, debugDev);\n return new RegExp(`^${tag}$`, 'u');\n}\n\nfunction areRequiredSubfieldsPresent(field) {\n const subfieldString = getMergeConstraintsForTag(field.tag, 'required').join('');\n if (subfieldString === null) {\n return true;\n } // nothing is required\n const subfieldArray = subfieldString.split('');\n return subfieldArray.every(sfcode => {\n const result = fieldHasSubfield(field, sfcode);\n if (!result) {\n debugDev(`Required subfield \u2021${sfcode} not found in '${fieldToString(field)}'!`);\n return false;\n }\n return true;\n });\n}\n\nfunction getUnbalancedPairedSubfieldCode(field1, field2) {\n const fullSubfieldString = getMergeConstraintsForTag(field1.tag, 'paired').join('') || '';\n\n if (fullSubfieldString === '') {\n return false;\n }\n\n // If the two fields share the FIN11 ID (WE SHOULD SUPPORT FIN13 AS WELL) there's no need to check the 'paired' constraint regarding related subfields.\n // Meaning that it this is FIN11 match we should not bother checking whether something like 100$b/c/d/q is there. (NB! Note that 'required' check is not alleviated in this way)\n // (I'm not saying that 100$b/c/d/q are in 'paired' contraint, I'm just illustrating the issue here)\n const pairable = pairableIdentifier(field1, field2, '(FIN11)');\n const subfieldString = pairable ? removeNameRelatedSubfieldCodes(fullSubfieldString, field1.tag) : fullSubfieldString;\n nvdebug(`CHECK ${pairable ? 'PAIRABLE ' : ''}${field1.tag} PAIRS: '${fullSubfieldString}' => '${subfieldString}'`, debugDev);\n\n if (subfieldString === '') {\n return false;\n }\n const subfieldArray = subfieldString.split('');\n\n return subfieldArray.find(sfcode => fieldHasNSubfields(field1, sfcode) !== fieldHasNSubfields(field2, sfcode));\n}\n\nfunction syntacticallyMergablePair(baseField, sourceField, config) {\n // Indicators must typically be equal (there are exceptions such as non-filing characters though):\n nvdebug(\"CHECK SYNTAX\", debugDev);\n if (!mergableIndicator1(baseField, sourceField, config)) {\n nvdebug(`non-mergable (reason: indicator1): ${JSON.stringify(config)}`, debugDev);\n return false;\n }\n\n if (!mergableIndicator2(baseField, sourceField, config)) {\n nvdebug(`non-mergable (reason: indicator2): ${JSON.stringify(config)}`, debugDev);\n return false;\n }\n\n if (!controlSubfieldsPermitMerge(baseField, sourceField)) {\n nvdebug('non-mergable (reason: control subfield)', debugDev);\n return false;\n }\n\n if (!provenanceSubfieldsPermitMerge(baseField, sourceField)) {\n nvdebug('non-mergable (reason: data provenance subfield)', debugDev);\n return false;\n }\n\n // NB! field1.tag and field2.tag might differ (1XX vs 7XX). Therefore required subfields might theoretically differ as well.\n // Note: Theoretically 260 $efg vs 264 with IND2=3 has already been handled by the preprocessor.\n // Thus check both:\n if (!areRequiredSubfieldsPresent(baseField) || !areRequiredSubfieldsPresent(sourceField)) {\n nvdebug('non-mergable (reason: missing subfields)', debugDev);\n return false;\n }\n\n // Stuff of Hacks! Eg. require that both fields either have or have not X00$t:\n const subfieldCodeThatFailsToPair = getUnbalancedPairedSubfieldCode(baseField, sourceField);\n if (subfieldCodeThatFailsToPair) {\n nvdebug(`non-mergable (reason: required subfield pair check failed for code: '${subfieldCodeThatFailsToPair}')`, debugDev);\n return false;\n }\n\n return true;\n}\n\nfunction mergablePair(baseField, sourceField, config) {\n if (!syntacticallyMergablePair(baseField, sourceField, config)) {\n nvdebug('non-mergable (reason: syntax)', debugDev);\n return false;\n }\n\n //debug('Test semantics...');\n if (!semanticallyMergablePair(baseField, sourceField)) {\n nvdebug('non-mergable (reason: semantics)', debugDev);\n return false;\n }\n\n nvdebug(`MERGABLE PAIR:\\n B: ${fieldToString(baseField)}\\n S: ${fieldToString(sourceField)}`, debugDev);\n return true;\n}\n\nfunction removeNameRelatedSubfieldCodes(codestring, tag) {\n // If we have $0 (FIN11) match, we are not interested in the core name subfields. Remove them from the subfield codes string.\n const removables = getNameRelatedSubfieldCodes(tag); // These are different for X00, X10 and X11...\n return removeCharsFromString(codestring, removables);\n\n function removeCharsFromString(string, removableCharsAsString) {\n const removableChars = removableCharsAsString.split('');\n return string.split('').filter(c => !removableChars.includes(c)).join('');\n }\n\n function getNameRelatedSubfieldCodes(tag) {\n if (['100', '600', '700', '800'].includes(tag)) {\n return 'abcdq';\n }\n if (['110', '610', '710', '810'].includes(tag)) {\n return 'abcdn';\n }\n if (['111', '611', '711', '811'].includes(tag)) {\n return 'acden';\n }\n return '';\n }\n}\n\nfunction pairableIdentifier(field1, field2, prefix) {\n const normalizedPrefix = prefix;\n nvdebug(`PREF '${prefix}' => '${normalizedPrefix}'`, debugDev);\n\n const prefixLength = normalizedPrefix.length;\n const identifiers1 = getIdentifiers(field1);\n if (identifiers1.length !== 1) {\n return false;\n }\n const identifiers2 = getIdentifiers(field2);\n if (identifiers2.length !== 1) {\n return false;\n }\n\n return identifiers1[0] === identifiers2[0];\n\n function getIdentifiers(field) {\n return field.subfields.filter(sf => sf.code === '0')\n .map(sf => normalizeControlSubfieldValue(sf.value))\n .filter(val => val.substring(0, prefixLength) === normalizedPrefix);\n }\n}\n\n\nfunction hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field) {\n // 700$s?\n if (field.tag === '260' || field.tag === '264') {\n return ['a', 'b', 'c', 'e', 'f', 'g'].some(subfieldCode => fieldHasMultipleSubfields(field, subfieldCode));\n }\n if (field.tag === '382') {\n return ['a', 'b', 'd', 'e', 'n', 'p'].some(subfieldCode => fieldHasMultipleSubfields(field, subfieldCode));\n }\n if (field.tag === '505') {\n return ['t', 'r', 'g'].some(subfieldCode => fieldHasMultipleSubfields(field, subfieldCode));\n }\n\n return false;\n}\n\nfunction getRelevantSubfieldValues(field, subfieldCode) {\n const values = field.subfields.filter(sf => sf.code === subfieldCode).map(sf => counterpartExtraNormalize(field.tag, subfieldCode, sf.value));\n\n return values.filter(v => valueCarriesMeaning(field.tag, subfieldCode, v));\n}\n\nfunction pairableValue(tag, subfieldCode, value1, value2) {\n if (value1 === value2) {\n return true;\n }\n\n // This function could just return true or false.\n // I thought of preference when I wrote this, but preference implemented *here* (modularity). mergeFields.js should handle preference.\n if (withAndWithoutQualifierAgree(value1, value2, tag, subfieldCode)) {\n // 300$a \"whatever\" and \"whatever (123 sivua)\"\n return true;\n }\n if (partsAgree(value1, value2, tag, subfieldCode) || corporateNamesAgree(value1, value2, tag, subfieldCode)) {\n // Pure baseness: here we assume that base's value1 is better than source's value2.\n return true;\n }\n\n return false;\n}\n\nfunction pairableValueInArray(tag, subfieldCode, val, arr) {\n return arr.some(val2 => pairableValue(tag, subfieldCode, val, val2));\n}\n\n\nfunction tightSubfieldMatch(field1, field2, subfieldCode, mustHave = false) {\n nvdebug(`${subfieldCode} F1: ${fieldToString(field1)}`, debugDev);\n nvdebug(`${subfieldCode} F2: ${fieldToString(field2)}`, debugDev);\n const values1 = getRelevantSubfieldValues(field1, subfieldCode);\n const values2 = getRelevantSubfieldValues(field2, subfieldCode);\n\n if(!mustHave) {\n if (values1.length === 0 || values2.length === 0) {\n return true;\n }\n }\n\n if (values1.length !== values2.length) {\n return false;\n }\n\n nvdebug(`Compare $${subfieldCode} contents:\\n '${values1.join(\"'\\n '\")}' vs\\n '${values2.join(\"'\\n '\")}'`, debugDev);\n return values1.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values2)) && values2.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values1));\n}\n\nfunction looseSubfieldMatch(field1, field2, subfieldCode) {\n const values1 = getRelevantSubfieldValues(field1, subfieldCode);\n const values2 = getRelevantSubfieldValues(field2, subfieldCode);\n if (values1.length === 0 || values2.length === 0) {\n return true;\n }\n // Subsets are fine:\n if (values1.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values2))) {\n return true;\n }\n if (values2.every(v => pairableValueInArray(field1.tag, subfieldCode, v, values1))) {\n return true;\n }\n return false;\n}\n\nfunction semanticallyMergablePair(baseField, sourceField) {\n const field1 = cloneAndNormalizeFieldForComparison(baseField);\n const field2 = cloneAndNormalizeFieldForComparison(sourceField);\n\n const string1 = fieldToString(field1);\n const string2 = fieldToString(field2);\n\n nvdebug(`IN ${baseField.tag}: pairableName():\\n '${string1}' vs\\n '${string2}'`, debugDev);\n if (string1 === string2) {\n return true;\n }\n\n const mergeConstraints = getMergeConstraintsForTag(field1.tag); // The tag doe\n if (mergeConstraints.length === 0) { // We have no constraints defined for this tag -> fail\n return false;\n }\n\n // Essentially these are too hard to handle with field-merge (eg. multi-505$g)\n if (hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field1) || hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field2)) {\n nvdebug(`Unmergable: data is too complex to be automatically safely merged`, debugDev);\n return false;\n }\n\n const asteriMatch = pairableIdentifier(field1, field2, '(FIN11)'); // If there's a match, there's no need to check the name (Caretaker will handle these.)\n // WE COULD REMOVE THESE FIELDS IN MERGE, SO THAT WE WON'T GET FUNNY NAMES).\n\n // NB! Currently we should get only one mergeContraint. However, should we support multiple merge contraints (= multiple profiles)?\n const allRequired = mergeConstraints[0].required || ''; // getMergeConstraintsForTag(field1.tag, 'required') || '';\n const reallyRequired = asteriMatch ? removeNameRelatedSubfieldCodes(allRequired, field1.tag) : allRequired;\n\n //nvdebug(`WP1: '${allRequired}' => ${reallyRequired}`, debugDev);\n if (!reallyRequired.split('').every(c => tightSubfieldMatch(field1, field2, c, true))) {\n return false;\n }\n\n const allPaired = mergeConstraints[0].paired || ''; // getMergeConstraintsForTag(field1.tag, 'paired') || '';\n const reallyPaired = asteriMatch ? removeNameRelatedSubfieldCodes(allPaired, field1.tag) : allPaired;\n //nvdebug(`WP2: '${allPaired}' => ${reallyPaired}`, debugDev);\n if (!reallyPaired.split('').every(c => tightSubfieldMatch(field1, field2, c, false))) {\n return false;\n }\n\n const allKeys = mergeConstraints[0].key || ''; // getMergeConstraintsForTag(field1.tag, 'key') || '';\n const relevantKeys = asteriMatch ? removeNameRelatedSubfieldCodes(allKeys, field1.tag) : allKeys\n //nvdebug(`WP3: keys='${allKeys}' => ${relevantKeys}`, debugDev);\n if (!relevantKeys.split('').every(c => looseSubfieldMatch(field1, field2, c))) {\n return false;\n }\n //nvdebug('WP4', debugDev);\n\n // required/paired/keys checks did not fail. Now check that did they really succeed\n if (allRequired.length > 0) { // I think we should use all here\n return true;\n }\n\n if (reallyPaired.length > 0 && field1.subfields.some(sf => reallyPaired.includes(sf.code))) {\n return true;\n }\n\n if(!tagIsRepeatable(field1.tag) || relevantKeys.length == 0) {\n return true;\n }\n\n // Raison d'\u00EAtre is long forgotten, but my educated guess about this: if 'key' is defined in merge constraints\n // for this field, then at least one of the subfield codes in 'key' must be present in both fields.\n // However, this is not necessarily right.\n if (relevantKeys.length > 0) {\n if (field1.subfields.some(sf => relevantKeys.includes(sf.code)) || field2.subfields.some(sf => relevantKeys.includes(sf.code))) { \n return relevantKeys.split('').some(code => hasCommonNominator(field1, field2, code));\n }\n }\n\n nvdebug(` name mismatch (${keys}):`, debugDev);\n nvdebug(` '${fieldToString(baseField)}' vs`, debugDev);\n nvdebug(` '${fieldToString(sourceField)}'`, debugDev);\n return false;\n}\n\nfunction getAlternativeNamesFrom9XX(record, field) {\n // Should we support 6XX and 8XX as well? Prolly not...\n if (!field.tag.match(/^(?:100|110|111|600|610|611|700|710|711)$/u)) {\n return [];\n }\n const tag = `9${field.tag.substring(1)}`;\n const cands = record.get(tag).filter(f => fieldHasSubfield(f, 'a') && fieldHasSubfield(f, 'y'));\n if (cands.length === 0) {\n return [];\n }\n const punctuationlessField = cloneAndRemovePunctuation(field);\n const [name] = punctuationlessField.subfields.filter(sf => sf.code === 'a').map(sf => sf.value);\n\n return cands.map(candField => getAltName(candField)).filter(val => val !== undefined);\n\n\n function getAltName(altField) {\n const [altA] = altField.subfields.filter(sf => sf.code === 'a').map(sf => sf.value);\n const [altY] = altField.subfields.filter(sf => sf.code === 'y').map(sf => sf.value);\n nvdebug(`Compare '${name}' vs '${altA}'/'${altY}'`, debugDev);\n if (name === altA) {\n return altY;\n }\n if (name === altY) {\n return altA;\n }\n nvdebug(` miss`, debugDev);\n return undefined;\n }\n\n}\n\n\nfunction mergablePairWithAltName(normCandField, normalizedField, altName, config) {\n // Replace source field $a name with alternative name and then compare:\n const [a] = normalizedField.subfields.filter(sf => sf.code === 'a');\n if (!a) {\n return false;\n }\n a.value = altName;\n\n return mergablePair(normCandField, normalizedField, config);\n}\n\nfunction getCounterpartIndex(field, counterpartCands, altNames, config) {\n const normalizedField = cloneAndNormalizeFieldForComparison(field);\n const normalizedCounterpartCands = counterpartCands.map(f => cloneAndNormalizeFieldForComparison(f));\n const index = normalizedCounterpartCands.findIndex(normCandField => mergablePair(normCandField, normalizedField, config));\n if (index > -1) {\n return index;\n }\n\n return normalizedCounterpartCands.findIndex(normCandField => altNames.some(altName => mergablePairWithAltName(normCandField, normalizedField, altName, config)));\n}\n\n\nfunction field264Exception(baseField, sourceRecord, sourceField, config) {\n if (baseField.tag !== '264') {\n return false;\n }\n\n if (sourceField.tag !== '264' || sourceRecord.get('264').length !== 1) {\n return false;\n }\n\n // Don't worry about semantics:\n return syntacticallyMergablePair(sourceField, baseField, config);\n}\n\nfunction getCounterpartCandidates(field, record) {\n const counterpartCands = record.get(tagToRegexp(field.tag, record.internalMerge));\n\n // MELKEHITYS-2969: copyright years should not merge with non-copyright years\n if (field.tag === '260' && isNotCopyrightYear(field)) {\n return counterpartCands.filter(candField => !isCopyrightField264(candField));\n }\n\n if (field.tag === '264' && isCopyrightField264(field)) { // Copyright year\n return counterpartCands.filter(candField => !isNotCopyrightYear(candField));\n }\n\n function isCopyrightField264(field) {\n return field.tag === '264' && field.ind2 === '4';\n }\n\n function isNotCopyrightYear(field) {\n if (field.tag === '264') {\n return !isCopyrightField264(field);\n }\n // Field 260: copyright year does not contain $a or $b:\n return !field.subfields.some(sf => sf.code === 'a' && sf.code === 'b');\n }\n\n return counterpartCands;\n\n}\n\nexport function baseIsSource(base, source) {\n base.localTest = true;\n const result = source.localTest;\n delete base.localTest;\n return result;\n}\n\nexport function getCounterpart(baseRecord, sourceRecord, field, config) {\n // First get relevant candidate fields. Note that 1XX and corresponding 7XX are considered equal, and tags 260 and 264 are lumped together.\n // (<= Note that self-merge behaves differently from two records here.)\n // Hacks: 973 can merge with 773, 940 can merge with 240 (but not the other way around)\n //nvdebug(`COUNTERPART FOR '${fieldToString(field)}'?`, debugDev);\n const counterpartCands = getCounterpartCandidates(field, baseRecord).filter(f => !f.mergeCandidate);\n\n if (!counterpartCands || counterpartCands.length === 0) {\n //nvdebug(`No counterpart(s) found for ${fieldToString(field)}`, debugDev);\n return null;\n }\n\n nvdebug(`Compare incoming '${fieldToString(field)}' with (up to) ${counterpartCands.length} existing field(s)`, debugDev);\n\n const normalizedField = cloneAndNormalizeFieldForComparison(field); // mainly strip punctuation here\n\n nvdebug(` Normalize incoming field to: '${fieldToString(normalizedField)}'`, debugDev);\n\n const uniqueAlternativeNames = getUniqueAlernativeNames();\n\n //nvdebug(` S: ${fieldToString(normalizedField)}`, debugDev);\n // Then find (the index of) the first mathing candidate field and return it.\n const index = getCounterpartIndex(normalizedField, counterpartCands, uniqueAlternativeNames, config);\n\n if (index > -1) {\n return counterpartCands[index];\n }\n\n // MET-456 exception\n if (counterpartCands.length === 1 && field264Exception(counterpartCands[0], sourceRecord, field, config)) {\n return counterpartCands[0];\n }\n\n return null;\n\n function getUniqueAlernativeNames() {\n if (baseIsSource(baseRecord, sourceRecord)) {\n return [];\n }\n // Try to look for alternative names from base and source record's 9XX fields:\n const alternativeNames = getAlternativeNamesFrom9XX(baseRecord, field).concat(getAlternativeNamesFrom9XX(sourceRecord, field));\n return alternativeNames.filter((name, i) => alternativeNames.indexOf(name) === i);\n }\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["suffix", "prefix", "name", "tag", "field"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import createDebugLogger from "debug";
|
|
2
1
|
import { marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value } from "../utils.js";
|
|
3
|
-
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator");
|
|
4
|
-
const debugDev = debug.extend("dev");
|
|
5
2
|
const ind1NonFilingChars = ["130", "630", "730", "740"];
|
|
6
3
|
const ind2NonFilingChars = ["222", "240", "242", "243", "245", "830"];
|
|
7
4
|
function marc21NoNeedToCheckInd1(tag) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/merge-fields/mergableIndicator.js"],
|
|
4
|
-
"sourcesContent": ["import createDebugLogger from 'debug';\nimport {marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value} from '../utils.js';\n\n// Specs: https://workgroups.helsinki.fi/x/K1ohCw (though we occasionally differ from them)...\n\
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport {marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value} from '../utils.js';\n\n// Specs: https://workgroups.helsinki.fi/x/K1ohCw (though we occasionally differ from them)...\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\nconst ind1NonFilingChars = ['130', '630', '730', '740'];\nconst ind2NonFilingChars = ['222', '240', '242', '243', '245', '830'];\n\nfunction marc21NoNeedToCheckInd1(tag) {\n const cands = marc21GetTagsLegalInd1Value(tag);\n if (typeof cands === 'string') { // single cand\n return true;\n }\n return false;\n}\n\nfunction marc21NoNeedToCheckInd2(tag) {\n const cands = marc21GetTagsLegalInd2Value(tag);\n if (typeof cands === 'string') { // single cand\n return true;\n }\n return false;\n}\n\n\nexport function mergableIndicator1(field1, field2, config) {\n // Indicators are identical:\n if (field1.ind1 === field2.ind1) {\n return true;\n }\n const {tag} = field1; // means \"tag = field1.tag\"\n // Indicator has but one legal value or is a non-filing indicator (NB: can not be overridden via config...):\n if (marc21NoNeedToCheckInd1(tag) || ind1NonFilingChars.includes(tag)) {\n return true;\n }\n // Override via config:\n if (config.ignoreIndicator1 && config.ignoreIndicator1.includes(tag)) {\n return true;\n }\n // Tolerate value '#' (reason: not spefified etc, the other value is supposedly a good one)\n if (field1.ind1 === ' ' || field2.ind1 === ' ') {\n return config.tolerateBlankIndicator1 && config.tolerateBlankIndicator1.includes(tag);\n }\n // Fail:\n return false;\n}\n\nexport function mergableIndicator2(field1, field2, config) {\n // Indicators are identical:\n if (field1.ind2 === field2.ind2) {\n return true;\n }\n\n // nvdebug(`mergableIndicator2\\n '${fieldToString(field1)}' vs\\n '${fieldToString(field2)}'`, debugDev);\n\n // NB! Our 260 vs 264 hacks...NB #2: We do this split check only for ind2, not for ind1.\n // Maybe reasons to this for ind1 will rise later on. None known yetr though.\n const tag1 = field1.tag;\n const tag2 = field2.tag;\n\n // Indicator has but one legal value or is a non-filing indicator (NB: can not be overridden via config...):\n if (marc21NoNeedToCheckInd2(tag1) || marc21NoNeedToCheckInd2(tag2) || ind2NonFilingChars.includes(tag1)) {\n return true;\n }\n\n // Override via config:\n if (config.ignoreIndicator2) {\n if (config.ignoreIndicator2.includes(tag1) || config.ignoreIndicator2.includes(tag2)) {\n return true;\n }\n }\n\n // Tolerate value '#' (reason: not spefified etc, the other value is supposedly a good one)\n if (config.tolerateBlankIndicator2) {\n if (field1.ind2 === ' ' && config.tolerateBlankIndicator2.includes(tag1)) {\n return true;\n }\n if (field2.ind2 === ' ' && config.tolerateBlankIndicator2.includes(tag2)) {\n return true;\n }\n\n }\n // Fail:\n return false;\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAQ,6BAA6B,mCAAkC;AAQvE,MAAM,qBAAqB,CAAC,OAAO,OAAO,OAAO,KAAK;AACtD,MAAM,qBAAqB,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAEpE,SAAS,wBAAwB,KAAK;AACpC,QAAM,QAAQ,4BAA4B,GAAG;AAC7C,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,KAAK;AACpC,QAAM,QAAQ,4BAA4B,GAAG;AAC7C,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGO,gBAAS,mBAAmB,QAAQ,QAAQ,QAAQ;AAEzD,MAAI,OAAO,SAAS,OAAO,MAAM;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,EAAC,IAAG,IAAI;AAEd,MAAI,wBAAwB,GAAG,KAAK,mBAAmB,SAAS,GAAG,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,oBAAoB,OAAO,iBAAiB,SAAS,GAAG,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAS,OAAO,OAAO,SAAS,KAAK;AAC9C,WAAO,OAAO,2BAA2B,OAAO,wBAAwB,SAAS,GAAG;AAAA,EACtF;AAEA,SAAO;AACT;AAEO,gBAAS,mBAAmB,QAAQ,QAAQ,QAAQ;AAEzD,MAAI,OAAO,SAAS,OAAO,MAAM;AAC/B,WAAO;AAAA,EACT;AAMA,QAAM,OAAO,OAAO;AACpB,QAAM,OAAO,OAAO;AAGpB,MAAI,wBAAwB,IAAI,KAAK,wBAAwB,IAAI,KAAK,mBAAmB,SAAS,IAAI,GAAG;AACvG,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,kBAAkB;AAC3B,QAAI,OAAO,iBAAiB,SAAS,IAAI,KAAK,OAAO,iBAAiB,SAAS,IAAI,GAAG;AACpF,aAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,OAAO,yBAAyB;AAClC,QAAI,OAAO,SAAS,OAAO,OAAO,wBAAwB,SAAS,IAAI,GAAG;AACxE,aAAO;AAAA,IACT;AACA,QAAI,OAAO,SAAS,OAAO,OAAO,wBAAwB,SAAS,IAAI,GAAG;AACxE,aAAO;AAAA,IACT;AAAA,EAEF;AAEA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/merge-fields/worldKnowledge.js"],
|
|
4
|
-
"sourcesContent": ["//import {nvdebug} from '../utils.js';\n\n// NB! This file (or at least synonyms) should eventually be moved away from merge to '..'.\n\n\nexport function valueCarriesMeaning(tag, subfieldCode, value) {\n // Some data is pretty meaningless and as meaningless is pretty close to nothing, this meaningless data should no prevent merge.\n // The list below is incomples (swedish translations etc)\n if (tag === '260' || tag === '264') {\n // We drop these, instead of normalizing, as KV does not put this information in place...\n if (subfieldCode === 'a') {\n if (value.match(/^[^a-z]*(?:Kustannuspaikka tuntematon|S\\.l)[^a-z]*$/ui)) {\n return false;\n }\n }\n if (subfieldCode === 'b') {\n if (value.match(/^[^a-z]*(?:Kustantaja tuntematon|S\\.n)[^a-z]*$/ui)) {\n return false;\n }\n }\n return true;\n }\n return true;\n}\n\nconst synonyms = [\n {tags: ['700', '710', '711', '730'], code: 'i', 'fin': 'Sis\u00E4lt\u00E4\u00E4 (ekspressio)', 'swe': 'Inneh\u00E5ller (uttryck)'},\n {tags: ['700', '710', '711', '730'], code: 'i', 'fin': 'Sis\u00E4lt\u00E4\u00E4 (teos)', 'swe': 'Inneh\u00E5ller (verk)'},\n {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Englanti', 'swe': 'Engelska'},\n {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Ruotsi', 'swe': 'Svenska'},\n {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Suomi', 'swe': 'Finska'}\n // There might eventually be need for a list of terms is given language (eg. engl. paperback and softcover)\n];\n\nexport function getSynonyms(term, tag = undefined, subfieldCode = undefined, preferredLanguage = undefined, ignoreCase = true, relevantLanguagesString = 'fin swe',) {\n if (!term) {\n return [];\n }\n //nvdebug(`WP1 CANDS: ${synonyms.length} FOR '${term}'
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["//import {nvdebug} from '../utils.js';\n//import createDebugLogger from 'debug';\n\n// NB! This file (or at least synonyms) should eventually be moved away from merge to '..'.\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:worldKnowledge');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\n\nexport function valueCarriesMeaning(tag, subfieldCode, value) {\n // Some data is pretty meaningless and as meaningless is pretty close to nothing, this meaningless data should no prevent merge.\n // The list below is incomples (swedish translations etc)\n if (tag === '260' || tag === '264') {\n // We drop these, instead of normalizing, as KV does not put this information in place...\n if (subfieldCode === 'a') {\n if (value.match(/^[^a-z]*(?:Kustannuspaikka tuntematon|S\\.l)[^a-z]*$/ui)) {\n return false;\n }\n }\n if (subfieldCode === 'b') {\n if (value.match(/^[^a-z]*(?:Kustantaja tuntematon|S\\.n)[^a-z]*$/ui)) {\n return false;\n }\n }\n return true;\n }\n return true;\n}\n\nconst synonyms = [\n {tags: ['700', '710', '711', '730'], code: 'i', 'fin': 'Sis\u00E4lt\u00E4\u00E4 (ekspressio)', 'swe': 'Inneh\u00E5ller (uttryck)'},\n {tags: ['700', '710', '711', '730'], code: 'i', 'fin': 'Sis\u00E4lt\u00E4\u00E4 (teos)', 'swe': 'Inneh\u00E5ller (verk)'},\n {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Englanti', 'swe': 'Engelska'},\n {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Ruotsi', 'swe': 'Svenska'},\n {tags: ['700', '710', '711', '730'], code: 'l', 'fin': 'Suomi', 'swe': 'Finska'}\n // There might eventually be need for a list of terms is given language (eg. engl. paperback and softcover)\n];\n\nexport function getSynonyms(term, tag = undefined, subfieldCode = undefined, preferredLanguage = undefined, ignoreCase = true, relevantLanguagesString = 'fin swe',) {\n if (!term) {\n return [];\n }\n //nvdebug(`WP1 CANDS: ${synonyms.length} FOR '${term}'`, debugDev);\n const relevantLanguges = relevantLanguagesString.split(/\\s+/u);\n const normalizedTerm = ignoreCase ? term.toLowerCase() : term;\n const synonymsWithTag = tag ? synonyms.filter(s => s.tags.includes(tag)) : synonyms;\n if (synonymsWithTag.length === 0) {\n return [];\n }\n //nvdebug(`WP2 (FILTER ${tag}) CANDS: ${synonymsWithTag.length}`, debugDev);\n const synonymsWithTagAndCode = subfieldCode ? synonymsWithTag.filter(s => s.code === subfieldCode) : synonymsWithTag;\n //nvdebug(`WP3 (FILTER $${subfieldCode}) CANDS: ${synonymsWithTagAndCode.length}:\\n${JSON.stringify(synonymsWithTagAndCode)}`, debugDev);\n const matchingSynonyms = synonymsWithTagAndCode.filter(s => termAndLangMatch(s));\n\n if (preferredLanguage && matchingSynonyms.length > 0) {\n //console.log(`USING PREFERRED LANG '${preferredLanguage}' for TERM '${term}':\\n${JSON.stringify(matchingSynonyms)}`, debugDev);\n return matchingSynonyms.map(s => s[preferredLanguage]);\n }\n return matchingSynonyms;\n\n function termAndLangMatch(synonym) {\n if (relevantLanguges.includes('fin')) {\n if (ignoreCase && synonym.fin.toLowerCase() === normalizedTerm ) {\n return true;\n }\n if (!ignoreCase && synonym.fin === term) {\n return true;\n }\n }\n\n if (relevantLanguges.includes('swe')) {\n if (ignoreCase && synonym.swe.toLowerCase() === normalizedTerm ) {\n return true;\n }\n if (!ignoreCase && synonym.swe === term) {\n return true;\n }\n }\n return false;\n }\n}\n\nexport function getSynonym(tag, subfieldCode, originalValue) {\n const finnishForm = getSynonyms(originalValue, tag, subfieldCode, 'fin');\n if (finnishForm.length === 1) {\n //nvdebug(`FINNISH FORM FOR ${tag}$${subfieldCode}: '${finnishForm[0]}'`, debugDev);\n return finnishForm[0];\n }\n return originalValue;\n}\n\nexport function normalizeForSamenessCheck(tag, subfieldCode, originalValue) {\n // NB! These work only for non-repeatable subfields!\n // Repeatable subfields are currently handled in mergeSubfields.js. Only non-repeatable subfields block field merge,\n // (This split is suboptiomal... Minimum fix: make this distinction cleaner...)\n\n //nvdebug(`TRYING TO DO ${tag}$${subfieldCode} '${originalValue}'`, debugDev);\n originalValue = getSynonym(tag, subfieldCode, originalValue);\n\n if (subfieldCode === 'a' && ['100', '600', '700', '800'].includes(tag)) { // \"Etunimi Sukunimi\"...\n return normalizePersonalName(originalValue);\n }\n\n // NB! originalValue should already be lowercased, stripped on initial '[' chars and postpunctuation.\n if (tag === '250' && subfieldCode === 'a') {\n return normalizeEditionStatement(originalValue);\n }\n\n // 506 - Restrictions on Access Note (R), $a - Terms governing access (NR)\n if (tag === '506' && subfieldCode === 'a') {\n return normalize506a(originalValue);\n }\n\n if (tag === '534' && subfieldCode === 'p') {\n return normalizeOriginalVersionNoteIntroductoryPhrase(originalValue);\n }\n\n return originalValue;\n}\n\n\nfunction normalizePersonalName(originalValue) {\n // Use more readable \"Forename Surname\" format in comparisons:\n return originalValue.replace(/^([^,]+), ([^,]+)$/u, '$2 $1');\n}\n\nconst sallittu506a = ['sallittu kaikenik\u00E4isille', 'sallittu', 's']; // downcased, without punctuation\nfunction normalize506a(originalValue) {\n if (sallittu506a.includes(originalValue)) {\n return sallittu506a[0];\n }\n return originalValue;\n}\n\nconst introductoryPhrasesMeaning1 = ['alkuper\u00E4inen', 'alkuper\u00E4isen julkaisutiedot', 'alun perin julkaistu', 'alunperin julkaistu'];\nfunction normalizeOriginalVersionNoteIntroductoryPhrase(originalValue) {\n // MELKEHITYS-1935-ish:\n if (introductoryPhrasesMeaning1.includes(originalValue)) {\n return introductoryPhrasesMeaning1[0];\n }\n\n return originalValue;\n}\n\nfunction normalizeEditionStatement(originalValue) {\n const value = originalValue;\n\n // As normalization tries to translate things info Finnish, use this for similarity check only!\n if (value.match(/^[1-9][0-9]*(?:\\.|:a|nd|rd|st|th) (?:ed\\.?|edition|p\\.?|painos|uppl\\.?|upplagan)[.\\]]*$/ui)) {\n const nth = value.replace(/[^0-9].*$/u, '');\n return `${nth}. painos`;\n }\n\n // Quick and dirty fix for\n if (value.match(/^[1-9][0-9]*(?:\\.|:a|nd|rd|st|th)(?: f\u00F6rnyade|,? rev\\.| uud\\.| uudistettu) (?:ed\\.?|edition|p\\.?|painos|uppl\\.?|upplagan)[.\\]]*$/ui)) {\n const nth = value.replace(/[^0-9].*$/u, '');\n return `${nth}. uudistettu painos`;\n }\n\n if (value.match(/^(?:First|F\u00F6rsta|Ensimm\u00E4inen) (?:ed\\.?|edition|p\\.?|painos|uppl\\.?|upplagan)[.\\]]*$/ui)) {\n return `1. painos`;\n }\n\n if (value.match(/^(?:Andra|Second|Toinen) (?:ed\\.?|edition|p\\.?|painos|uppl\\.?|upplagan)[.\\]]*$/ui)) {\n return `2. painos`;\n }\n\n if (value.match(/^(?:Kolmas|Third|Tredje) (?:ed\\.?|edition|p\\.?|painos|uppl\\.?|upplagan)[.\\]]*$/ui)) {\n return `3. painos`;\n }\n\n if (value.match(/^(?:Fourth|Fj\u00E4rde|Nelj\u00E4s) (?:ed\\.?|edition|p\\.?|painos|uppl\\.?|upplagan)[.\\]]*$/ui)) {\n return `4. painos`;\n }\n\n return originalValue;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,9 @@ import { fieldFixPunctuation, fieldStripPunctuation } from "./punctuation2.js";
|
|
|
3
3
|
import { fieldToString, nvdebug } from "./utils.js";
|
|
4
4
|
import { sortAdjacentSubfields } from "./sortSubfields.js";
|
|
5
5
|
import { sortAdjacentRelatorTerms, tagToRelatorTermSubfieldCode } from "./sortRelatorTerms.js";
|
|
6
|
+
import createDebugLogger from "debug";
|
|
7
|
+
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields");
|
|
8
|
+
const debugDev = debug.extend("dev");
|
|
6
9
|
export default function() {
|
|
7
10
|
return {
|
|
8
11
|
description: "Merge author fields that only differ in $e relator terms",
|
|
@@ -52,26 +55,26 @@ function mergeRelatorTermFields(record, fix = false) {
|
|
|
52
55
|
let fields = record.get("(?:[17][01]0|720)");
|
|
53
56
|
let result = [];
|
|
54
57
|
const comparisonFieldsAsString = fields.map((f) => fieldToString(createNormalizedCloneWithoutRelatorTerms(f)));
|
|
55
|
-
nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found
|
|
58
|
+
nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`, debugDev);
|
|
56
59
|
for (let i = 0; i < fields.length - 1; i++) {
|
|
57
60
|
let currField = fields[i];
|
|
58
61
|
if (currField.deleted) {
|
|
59
62
|
continue;
|
|
60
63
|
}
|
|
61
|
-
nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}
|
|
64
|
+
nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`, debugDev);
|
|
62
65
|
for (let j = i + 1; j < fields.length; j++) {
|
|
63
|
-
nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}
|
|
66
|
+
nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`, debugDev);
|
|
64
67
|
let mergableField = fields[j];
|
|
65
68
|
if (comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {
|
|
66
|
-
nvdebug(" NOT PAIR");
|
|
69
|
+
nvdebug(" NOT PAIR", debugDev);
|
|
67
70
|
continue;
|
|
68
71
|
}
|
|
69
72
|
if (mergableField.deleted) {
|
|
70
|
-
nvdebug(" DELETED");
|
|
73
|
+
nvdebug(" DELETED", debugDev);
|
|
71
74
|
continue;
|
|
72
75
|
}
|
|
73
76
|
const str = `MERGE RELATOR TERM FIELD: ${fieldToString(mergableField)}`;
|
|
74
|
-
nvdebug(str);
|
|
77
|
+
nvdebug(str, debugDev);
|
|
75
78
|
if (!result.includes(str)) {
|
|
76
79
|
result.push(str);
|
|
77
80
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/mergeRelatorTermFields.js"],
|
|
4
|
-
"sourcesContent": ["// Merge author/agent fields\n//\n// Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.\n// These fields can be merged (and $e-subfields can then be sorted)...\n//\n// Author(s): Nicholas Volk\n\n\nimport clone from 'clone';\nimport {fieldFixPunctuation, fieldStripPunctuation} from './punctuation2.js';\nimport {fieldToString, nvdebug} from './utils.js';\nimport {sortAdjacentSubfields} from './sortSubfields.js';\nimport {sortAdjacentRelatorTerms, tagToRelatorTermSubfieldCode} from './sortRelatorTerms.js';\
|
|
5
|
-
"mappings": "AAQA,OAAO,WAAW;AAClB,SAAQ,qBAAqB,6BAA4B;AACzD,SAAQ,eAAe,eAAc;AACrC,SAAQ,6BAA4B;AACpC,SAAQ,0BAA0B,oCAAmC;
|
|
4
|
+
"sourcesContent": ["// Merge author/agent fields\n//\n// Rationale: Same author can appear in one 1XX and multiple 7XX fields having only different $e subfields.\n// These fields can be merged (and $e-subfields can then be sorted)...\n//\n// Author(s): Nicholas Volk\n\n\nimport clone from 'clone';\nimport {fieldFixPunctuation, fieldStripPunctuation} from './punctuation2.js';\nimport {fieldToString, nvdebug} from './utils.js';\nimport {sortAdjacentSubfields} from './sortSubfields.js';\nimport {sortAdjacentRelatorTerms, tagToRelatorTermSubfieldCode} from './sortRelatorTerms.js';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeRelatorTermFields');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\n\nexport default function () {\n\n return {\n description: 'Merge author fields that only differ in $e relator terms',\n validate, fix\n };\n\n function fix(record) {\n const msg = mergeRelatorTermFields(record, true);\n const res = {message: msg, fix: msg, valid: true};\n return res;\n }\n\n function validate(record) {\n const msg = mergeRelatorTermFields(record, false);\n const res = {message: msg};\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n}\n\nfunction createNormalizedClone(field) {\n const clonedField = clone(field);\n // Normalize\n fieldStripPunctuation(clonedField);\n return clonedField;\n}\n\nfunction createNormalizedCloneWithoutRelatorTerms(field) {\n const clonedField = createNormalizedClone(field);\n // Remove relator terms $e subfi:\n clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== 'e');\n return clonedField;\n}\n\nfunction getRelatorTermStrings(relatorTermSubfieldCode, field) {\n return field.subfields.filter(sf => sf.code === relatorTermSubfieldCode).map(sf => sf.value);\n\n}\n\nfunction extractAddableRelatorTerms(fromField, toField) {\n const relatorTermSubfieldCode = tagToRelatorTermSubfieldCode(fromField.tag);\n const normalizedFromFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, fromField);\n if (normalizedFromFieldRelatorTerms.length === 0) {\n return [];\n }\n // Remove values that already exist:\n const normalizedToFieldRelatorTerms = getRelatorTermStrings(relatorTermSubfieldCode, toField);\n return normalizedFromFieldRelatorTerms.filter(str => !normalizedToFieldRelatorTerms.includes(str));\n}\n\n\nfunction copyRelatorSubfields(fromField, toField) {\n const relatorTermSubfieldCode = tagToRelatorTermSubfieldCode(fromField.tag);\n const newRelatorTerms = extractAddableRelatorTerms(fromField, toField);\n\n newRelatorTerms.forEach(term => toField.subfields.push({code: relatorTermSubfieldCode, value: term}));\n\n}\n\nfunction mergeRelatorTermFields(record, fix = false) {\n // NV: 111/711, 751 and 752 where so rare that I did not add them here. Can't remember why I skipped 6XX and 8XX...\n let fields = record.get('(?:[17][01]0|720)');\n let result = [];\n const comparisonFieldsAsString = fields.map(f => fieldToString(createNormalizedCloneWithoutRelatorTerms(f)));\n\n nvdebug(`mergeRelatorTermFields(): ${fields.length} cand field(s) found`, debugDev);\n for(let i=0; i < fields.length-1; i++) {\n let currField = fields[i];\n if (currField.deleted) {\n continue;\n }\n nvdebug(`RT: Trying to pair ${comparisonFieldsAsString[i]}/${i}`, debugDev);\n for (let j=i+1; j < fields.length; j++) {\n nvdebug(` Compare with ${comparisonFieldsAsString[j]}/${j}`, debugDev);\n let mergableField = fields[j];\n // Skip 1/7 from 1XX/7XX for similarity check:\n if ( comparisonFieldsAsString[i].substring(1) !== comparisonFieldsAsString[j].substring(1)) {\n nvdebug(\" NOT PAIR\", debugDev);\n continue;\n }\n if (mergableField.deleted) {\n nvdebug(\" DELETED\", debugDev);\n continue;\n }\n const str = `MERGE RELATOR TERM FIELD: ${fieldToString(mergableField)}`;\n nvdebug(str, debugDev);\n\n if(!result.includes(str)) {\n result.push(str)\n }\n\n if (fix) {\n mergableField.deleted = 1;\n copyRelatorSubfields(mergableField, currField);\n fieldFixPunctuation(currField);\n sortAdjacentSubfields(currField); // Put the added $e subfield to proper places.\n sortAdjacentRelatorTerms(currField); // Sort $e subfields with each other\n fieldFixPunctuation(currField);\n\n }\n }\n }\n\n if(!fix) {\n fields.forEach(f => delete f.deleted);\n }\n\n record.fields = record.fields.filter(f => !f.deleted);\n return result;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/normalize-dashes.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import clone from "clone";
|
|
2
2
|
import { fieldToString, isContentSubfieldCode, nvdebug } from "./utils.js";
|
|
3
|
+
import createDebugLogger from "debug";
|
|
4
|
+
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:normaliza-dashes");
|
|
5
|
+
const debugDev = debug.extend("dev");
|
|
3
6
|
export default function() {
|
|
4
7
|
return {
|
|
5
8
|
description: 'Normalize various dashes to "-"',
|
|
@@ -7,7 +10,7 @@ export default function() {
|
|
|
7
10
|
fix
|
|
8
11
|
};
|
|
9
12
|
function fix(record) {
|
|
10
|
-
nvdebug(`FIX ME
|
|
13
|
+
nvdebug(`FIX ME`, debugDev);
|
|
11
14
|
record.fields.forEach((field) => {
|
|
12
15
|
fixDashes(field);
|
|
13
16
|
});
|
|
@@ -16,7 +19,7 @@ export default function() {
|
|
|
16
19
|
}
|
|
17
20
|
function validate(record) {
|
|
18
21
|
const res = { message: [] };
|
|
19
|
-
nvdebug(`VALIDATE ME
|
|
22
|
+
nvdebug(`VALIDATE ME`, debugDev);
|
|
20
23
|
record.fields?.forEach((field) => {
|
|
21
24
|
validateField(field, res);
|
|
22
25
|
});
|
|
@@ -25,7 +28,7 @@ export default function() {
|
|
|
25
28
|
}
|
|
26
29
|
function validateField(field, res) {
|
|
27
30
|
const orig = fieldToString(field);
|
|
28
|
-
nvdebug(` VALIDATE FIELD '${orig}'
|
|
31
|
+
nvdebug(` VALIDATE FIELD '${orig}'`, debugDev);
|
|
29
32
|
const normalizedField = fixDashes(clone(field));
|
|
30
33
|
const mod = fieldToString(normalizedField);
|
|
31
34
|
if (orig === mod) {
|
|
@@ -39,7 +42,7 @@ function fixDashes(field) {
|
|
|
39
42
|
if (!field.subfields) {
|
|
40
43
|
return field;
|
|
41
44
|
}
|
|
42
|
-
nvdebug(`Dashing ${fieldToString(field)}
|
|
45
|
+
nvdebug(`Dashing ${fieldToString(field)}`, debugDev);
|
|
43
46
|
field.subfields.forEach((sf) => subfieldFixDashes(sf));
|
|
44
47
|
return field;
|
|
45
48
|
function subfieldFixDashes(subfield) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/normalize-dashes.js"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import clone from 'clone';\nimport {fieldToString, isContentSubfieldCode, nvdebug} from './utils.js';\n\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normaliza-dashes');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Normalize various dashes to \"-\"',\n validate, fix\n };\n\n function fix(record) {\n nvdebug(`FIX ME`, debugDev);\n record.fields.forEach(field => {\n fixDashes(field);\n });\n\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n nvdebug(`VALIDATE ME`, debugDev);\n record.fields?.forEach(field => {\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n\n function validateField(field, res) {\n const orig = fieldToString(field);\n nvdebug(` VALIDATE FIELD '${orig}'`, debugDev);\n\n const normalizedField = fixDashes(clone(field));\n const mod = fieldToString(normalizedField);\n if (orig === mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n return;\n }\n res.message.push(`'TODO: ${orig}' => '${mod}'`);\n return;\n }\n}\n\n\nfunction fixDashes(field) {\n if (!field.subfields) {\n return field;\n }\n\n nvdebug(`Dashing ${fieldToString(field)}`, debugDev);\n\n field.subfields.forEach(sf => subfieldFixDashes(sf));\n\n return field;\n\n function subfieldFixDashes(subfield) {\n if (!isContentSubfieldCode(subfield.code, field.tag)) {\n return;\n }\n // Normalize dashes U+2010 ... U+2015 to '-':\n subfield.value = subfield.value.replace(/[\\u2010\\u2011\\u2012\\u2013\\u2014\\u2015]/ug, '-');\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAQ,eAAe,uBAAuB,eAAc;AAE5D,OAAO,uBAAuB;AAE9B,MAAM,QAAQ,kBAAkB,2DAA2D;AAE3F,MAAM,WAAW,MAAM,OAAO,KAAK;AAInC,0BAA2B;AAEzB,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IAAU;AAAA,EACZ;AAEA,WAAS,IAAI,QAAQ;AACnB,YAAQ,UAAU,QAAQ;AAC1B,WAAO,OAAO,QAAQ,WAAS;AAC7B,gBAAU,KAAK;AAAA,IACjB,CAAC;AAED,UAAM,MAAM,EAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,KAAI;AAC9C,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,QAAQ;AACxB,UAAM,MAAM,EAAC,SAAS,CAAC,EAAC;AAExB,YAAQ,eAAe,QAAQ;AAC/B,WAAO,QAAQ,QAAQ,WAAS;AAC9B,oBAAc,OAAO,GAAG;AAAA,IAC1B,CAAC;AAED,QAAI,QAAQ,EAAE,IAAI,QAAQ,UAAU;AACpC,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,OAAO,KAAK;AACjC,UAAM,OAAO,cAAc,KAAK;AAChC,YAAQ,oBAAoB,IAAI,KAAK,QAAQ;AAE7C,UAAM,kBAAkB,UAAU,MAAM,KAAK,CAAC;AAC9C,UAAM,MAAM,cAAc,eAAe;AACzC,QAAI,SAAS,KAAK;AAChB;AAAA,IACF;AACA,QAAI,QAAQ,KAAK,UAAU,IAAI,SAAS,GAAG,GAAG;AAC9C;AAAA,EACF;AACF;AAGA,SAAS,UAAU,OAAO;AACxB,MAAI,CAAC,MAAM,WAAW;AACpB,WAAO;AAAA,EACT;AAEA,UAAQ,WAAW,cAAc,KAAK,CAAC,IAAI,QAAQ;AAEnD,QAAM,UAAU,QAAQ,QAAM,kBAAkB,EAAE,CAAC;AAEnD,SAAO;AAEP,WAAS,kBAAkB,UAAU;AACnC,QAAI,CAAC,sBAAsB,SAAS,MAAM,MAAM,GAAG,GAAG;AACpD;AAAA,IACF;AAEA,aAAS,QAAQ,SAAS,MAAM,QAAQ,4CAA4C,GAAG;AAAA,EACzF;AAEF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/normalize-identifiers.js"],
|
|
4
|
-
"sourcesContent": ["// Relocated from melinda-marc-record-merge-reducers (and renamed)\
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["// Relocated from melinda-marc-record-merge-reducers (and renamed)\nimport clone from 'clone';\nimport {fieldToString, /*nvdebug*/} from './utils.js';\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalize-identifiers');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\nexport default function () {\n\n // NB! We should and could handle ISNIs here as well.\n return {\n description: 'Normalizes identifiers such as subfield $0 values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = [];\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n //nvdebug(`NORMALIZE CONTROL NUMBER FIX`, debugDev);\n record.fields.forEach(field => {\n //nvdebug(` NORMALIZE CONTROL NUMBER FIX ${fieldToString(field)}`, debugDev);\n\n fieldNormalizeControlNumbers(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1);\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n //nvdebug(`NORMALIZE CONTROL NUMBER VALIDATE`, debugDev);\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n //nvdebug(` NORMALIZE CONTROL NUMBER VALIDATE ${fieldToString(field)}`, debugDev);\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n\n const normalizedField = clone(field);\n fieldNormalizeControlNumbers(normalizedField);\n\n const orig = fieldToString(field);\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' could do with control number identifier normalization`);\n return;\n }\n\n return;\n }\n}\n\nconst alephInternal01 = '(FIN01)';\nconst alephInternal10 = '(FIN10)';\nconst alephInternal11 = '(FIN11)';\nconst alephInternal12 = '(FIN12)';\nconst alephInternal13 = '(FIN13)';\n\nconst standard01 = '(FI-MELINDA)';\nconst standard10 = '(FI-ASTERI-S)';\nconst standard11 = '(FI-ASTERI-N)';\nconst standard12 = '(FI-ASTERI-A)';\nconst standard13 = '(FI-ASTERI-W)';\n\nconst both01 = {ALEPH_INTERNAL: alephInternal01, STANDARD: standard01};\nconst both10 = {ALEPH_INTERNAL: alephInternal10, STANDARD: standard10};\nconst both11 = {ALEPH_INTERNAL: alephInternal11, STANDARD: standard11};\nconst both12 = {ALEPH_INTERNAL: alephInternal12, STANDARD: standard12};\nconst both13 = {ALEPH_INTERNAL: alephInternal13, STANDARD: standard13};\n\nconst mappings = {\n 'FCC': both01,\n '(FI-ASTERI-A)': both12,\n '(FI-ASTERI-N)': both11,\n '(FI-ASTERI-S)': both10,\n '(FI-ASTERI-W)': both13,\n '(FI-MELINDA)': both01,\n '(FIN01)': both01,\n '(FIN10)': both10,\n '(FIN11)': both11,\n '(FIN12)': both12,\n '(FIN13)': both13,\n 'http://urn.fi/URN:NBN:fi:au:finaf:': both11,\n 'https://urn.fi/URN:NBN:fi:au:finaf:': both11\n};\n\nfunction normalizeNineDigitIDs(value, targetFormat = 'ALEPH_INTERNAL') {\n // $value should be prefix + nine-digits. Do nothing if nine-digit tail condition is not met:\n const nineDigitTail = value.slice(-9);\n if (!(/^[0-9]{9}$/u).test(nineDigitTail)) {\n return value;\n }\n // Normalize prefix:\n const currPrefix = value.slice(0, -9);\n\n if (currPrefix in mappings) {\n //nvdebug(`${currPrefix}, TF:${targetFormat}...`, debugDev);\n //nvdebug(`${JSON.stringify(mappings[currPrefix])}`, debugDev);\n return `${mappings[currPrefix][targetFormat]}${nineDigitTail}`;\n }\n return value;\n}\n\nexport function isIsni(value) {\n if ((/^\\(isni\\)(?: ?[0-9]{4}){4}$/u).test(value)) {\n return true;\n }\n if ((/^https:\\/\\/isni.org\\/isni\\/[0-9]{16}$/u).test(value)) {\n return true;\n }\n return false;\n}\n\nexport function normalizeIsni(value) {\n if (isIsni(value)) {\n return `https://isni.org/isni/${value.replace(/[^0-9]/gu, '')}`;\n }\n return value;\n}\n\n\nexport function normalizeControlSubfieldValue(value = '', targetFormat = 'ALEPH_INTERNAL') {\n if (isIsni(value)) {\n return normalizeIsni(value);\n }\n\n const normalizedValue = normalizeNineDigitIDs(value, targetFormat);\n if (normalizedValue !== value) {\n return normalizedValue;\n }\n\n // Something for isni IDs?\n return value;\n}\n\n//export function normalizableSubfieldPrefix(tag, sf) {\nexport function normalizeAs(tag, subfieldCode) {\n //nvdebug(`nAs ${tag}, ${subfieldCode}`, debugDev);\n if (subfieldCode === '0' || subfieldCode === '1' || subfieldCode === 'w') {\n return 'ALEPH_INTERNAL';\n }\n\n if (tag === '035' && ['a', 'z'].includes(subfieldCode)) {\n return 'STANDARD';\n }\n return undefined;\n}\n\nexport function fieldNormalizeControlNumbers(field) {\n // Rename \"Prefixes\" as \"ControlNumberIdentifiers\"?\n // No, since isni etc... however, just \"ControlNumber\" would do...\n // \"identifiers\" ?\n if (!field.subfields) {\n return;\n }\n\n field.subfields.forEach(sf => {\n const targetFormat = normalizeAs(field.tag, sf.code);\n if (targetFormat !== undefined) {\n //nvdebug(`NORMALIZE SUBFIELD $${sf.code} IN FIELD: '${fieldToString(field)}' TO ${targetFormat}`, debugDev);\n sf.value = normalizeControlSubfieldValue(sf.value, targetFormat);\n return;\n }\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/normalize-utf8-diacritics.js"],
|
|
4
|
-
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport {convert as nongenericNormalization} from './unicode-decomposition.js';\nimport {fieldToString} from './utils.js';\n\n// Note that https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js contains\n// similar functionalities. It's less generic and lacks diacritic removal but has it advantages as well.\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/normalize-utf-diacritics');\n\n// See also https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js .\n// It uses a list of convertable characters whilst this uses a generic stuff as well.\n// It handles various '.' and '\u00A9' type normalizations as well.\n// NB! This version has minor bug/feature issue regarding fixComposition()\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Generic normalization of latin UTF-8 diacritics. Precompose Finnish \u00E5, \u00E4 and \u00F6. Decompose others.',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = [];\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n fieldFixComposition(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1);\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n const orig = fieldToString(field);\n\n const normalizedField = fieldFixComposition(clone(field));\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' requires normalization`);\n return;\n }\n return;\n }\n}\n\n\n// Traditionally these six are precomposed and all the rest decomposed\nexport function precomposeFinnishLetters(value = '') {\n return value.\n replace(/a\u030A/gu, '\u00E5').\n replace(/a\u0308/gu, '\u00E4').\n replace(/o\u0308/gu, '\u00F6').\n replace(/A\u030A/gu, '\u00C5').\n replace(/A\u0308/gu, '\u00C4').\n replace(/O\u0308/gu, '\u00D6');\n}\n\nexport function fixComposition(value = '') {\n // Target: Diacritics use Melinda internal notation.\n // General solution: Decompose everything and then compose '\u00E5', '\u00E4', '\u00F6', '\u00C5', '\u00C4' and '\u00D6'.\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n // Bug/Feature: the generic normalize() function also normalizes non-latin encodings as well, is this ok?\n // Exception: Input contains non-Latin script letters: don't decompose (see field 880 tests):\n if (value.match(/[^\\p{Script=Latin}\\p{Script=Common}\\p{Script=Inherited}]/u)) {\n // Problem with this approach: mixed language content (eg. cyrillic + latin) won't get normalized.\n // Hack/Damage control: we might add decomposition rules for most common diacritis here (eg. \u00FC, \u00E9...).\n // OR we could split input to words and handle them separately?\n // NB! Hack not implemented yet. The main source of problematic case would probably be greek characters\n // within texts, that are written with latin alphabet.\n //return precomposeFinnishLetters(value);\n return nongenericNormalization(value);\n }\n return precomposeFinnishLetters(String(value).normalize('NFD'));\n}\n\n\nexport function fieldFixComposition(field) {\n if (!field.subfields) {\n return field;\n }\n //const originalValue = fieldToString(field);\n //nvdebug(`fFC: '${originalValue}'`,
|
|
5
|
-
"mappings": "AACA,OAAO,WAAW;AAClB,SAAQ,WAAW,+BAA8B;AACjD,SAAQ,
|
|
4
|
+
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport {convert as nongenericNormalization} from './unicode-decomposition.js';\nimport {fieldToString /*, nvdebug */} from './utils.js';\n\n// Note that https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js contains\n// similar functionalities. It's less generic and lacks diacritic removal but has it advantages as well.\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/normalize-utf-diacritics');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\n\n// See also https://github.com/NatLibFi/marc-record-validators-melinda/blob/master/src/unicode-decomposition.js .\n// It uses a list of convertable characters whilst this uses a generic stuff as well.\n// It handles various '.' and '\u00A9' type normalizations as well.\n// NB! This version has minor bug/feature issue regarding fixComposition()\n\n// Author(s): Nicholas Volk\nexport default function () {\n\n return {\n description: 'Generic normalization of latin UTF-8 diacritics. Precompose Finnish \u00E5, \u00E4 and \u00F6. Decompose others.',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n //message.fix = [];\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n fieldFixComposition(field);\n //validateField(field, true, message);\n });\n\n // message.valid = !(message.message.length >= 1);\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n // Actual parsing of all fields\n /*\n if (!record.fields) {\n return false;\n }\n */\n\n record.fields.forEach(field => {\n validateField(field, res);\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n\n function validateField(field, res) {\n if (!field.subfields) {\n return;\n }\n const orig = fieldToString(field);\n\n const normalizedField = fieldFixComposition(clone(field));\n const mod = fieldToString(normalizedField);\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`'${orig}' requires normalization`);\n return;\n }\n return;\n }\n}\n\n\n// Traditionally these six are precomposed and all the rest decomposed\nexport function precomposeFinnishLetters(value = '') {\n return value.\n replace(/a\u030A/gu, '\u00E5').\n replace(/a\u0308/gu, '\u00E4').\n replace(/o\u0308/gu, '\u00F6').\n replace(/A\u030A/gu, '\u00C5').\n replace(/A\u0308/gu, '\u00C4').\n replace(/O\u0308/gu, '\u00D6');\n}\n\nexport function fixComposition(value = '') {\n // Target: Diacritics use Melinda internal notation.\n // General solution: Decompose everything and then compose '\u00E5', '\u00E4', '\u00F6', '\u00C5', '\u00C4' and '\u00D6'.\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n // Bug/Feature: the generic normalize() function also normalizes non-latin encodings as well, is this ok?\n // Exception: Input contains non-Latin script letters: don't decompose (see field 880 tests):\n if (value.match(/[^\\p{Script=Latin}\\p{Script=Common}\\p{Script=Inherited}]/u)) {\n // Problem with this approach: mixed language content (eg. cyrillic + latin) won't get normalized.\n // Hack/Damage control: we might add decomposition rules for most common diacritis here (eg. \u00FC, \u00E9...).\n // OR we could split input to words and handle them separately?\n // NB! Hack not implemented yet. The main source of problematic case would probably be greek characters\n // within texts, that are written with latin alphabet.\n //return precomposeFinnishLetters(value);\n return nongenericNormalization(value);\n }\n return precomposeFinnishLetters(String(value).normalize('NFD'));\n}\n\n\nexport function fieldFixComposition(field) {\n if (!field.subfields) {\n return field;\n }\n //const originalValue = fieldToString(field);\n //nvdebug(`fFC: '${originalValue}'`, debugDev);\n field.subfields.forEach((subfield, index) => {\n field.subfields[index].value = fixComposition(subfield.value);\n });\n //const newValue = fieldToString(field);\n //if (originalValue !== newValue) {\n // nvdebug(`FIXCOMP: '${originalValue}' => '${newValue}'`, debugDev);\n //}\n return field;\n}\n\n/*\nexport function fieldRemoveDecomposedDiacritics(field) {\n // Raison d'\u00EAtre/motivation: \"Sir\u00E9n\" and diacriticless \"Siren\" might refer to a same surname, so this normalization\n // allows us to compare authors and avoid duplicate fields.\n field.subfields.forEach((sf) => {\n sf.value = removeDecomposedDiacritics(sf.value);\n });\n\n function removeDecomposedDiacritics(value = '') {\n // NB #1: Does nothing to precomposed letters. String.normalize('NFD') can handle them.\n // NB #2: Finnish letters '\u00E5', '\u00E4', '\u00F6', '\u00C5', \u00C4', and '\u00D6' should be handled (=precomposed) before calling this.\n // NB #3: Calling our very own fixComposition() before this function handles both #1 and #2.\n return String(value).replace(/\\p{Diacritic}/gu, '');\n }\n}\n*/\n\n"],
|
|
5
|
+
"mappings": "AACA,OAAO,WAAW;AAClB,SAAQ,WAAW,+BAA8B;AACjD,SAAQ,qBAAmC;AAgB3C,0BAA2B;AAEzB,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IAAU;AAAA,EACZ;AAEA,WAAS,IAAI,QAAQ;AACnB,UAAM,MAAM,EAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,KAAI;AAU9C,WAAO,OAAO,QAAQ,WAAS;AAC7B,0BAAoB,KAAK;AAAA,IAE3B,CAAC;AAGD,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,QAAQ;AACxB,UAAM,MAAM,EAAC,SAAS,CAAC,EAAC;AASxB,WAAO,OAAO,QAAQ,WAAS;AAC7B,oBAAc,OAAO,GAAG;AAAA,IAC1B,CAAC;AAED,QAAI,QAAQ,EAAE,IAAI,QAAQ,UAAU;AACpC,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,OAAO,KAAK;AACjC,QAAI,CAAC,MAAM,WAAW;AACpB;AAAA,IACF;AACA,UAAM,OAAO,cAAc,KAAK;AAEhC,UAAM,kBAAkB,oBAAoB,MAAM,KAAK,CAAC;AACxD,UAAM,MAAM,cAAc,eAAe;AACzC,QAAI,SAAS,KAAK;AAChB,UAAI,QAAQ,KAAK,IAAI,IAAI,0BAA0B;AACnD;AAAA,IACF;AACA;AAAA,EACF;AACF;AAIO,gBAAS,yBAAyB,QAAQ,IAAI;AACnD,SAAO,MACL,QAAQ,QAAQ,MAAG,EACnB,QAAQ,QAAQ,MAAG,EACnB,QAAQ,QAAQ,MAAG,EACnB,QAAQ,QAAQ,MAAG,EACnB,QAAQ,QAAQ,MAAG,EACnB,QAAQ,QAAQ,MAAG;AACvB;AAEO,gBAAS,eAAe,QAAQ,IAAI;AAMzC,MAAI,MAAM,MAAM,2DAA2D,GAAG;AAO5E,WAAO,wBAAwB,KAAK;AAAA,EACtC;AACA,SAAO,yBAAyB,OAAO,KAAK,EAAE,UAAU,KAAK,CAAC;AAChE;AAGO,gBAAS,oBAAoB,OAAO;AACzC,MAAI,CAAC,MAAM,WAAW;AACpB,WAAO;AAAA,EACT;AAGA,QAAM,UAAU,QAAQ,CAAC,UAAU,UAAU;AAC3C,UAAM,UAAU,KAAK,EAAE,QAAQ,eAAe,SAAS,KAAK;AAAA,EAC9D,CAAC;AAKD,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|