@natlibfi/marc-record-validators-melinda 12.0.6 → 12.0.7

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.
Files changed (120) hide show
  1. package/dist/cyrillux.js +11 -11
  2. package/dist/cyrillux.js.map +2 -2
  3. package/dist/dataProvenanceUtils.js +19 -0
  4. package/dist/dataProvenanceUtils.js.map +7 -0
  5. package/dist/index.js +3 -1
  6. package/dist/index.js.map +2 -2
  7. package/dist/merge-fields/controlSubfields.js.map +2 -2
  8. package/dist/merge-fields/counterpartField.js +149 -152
  9. package/dist/merge-fields/counterpartField.js.map +3 -3
  10. package/dist/merge-fields/dataProvenance.js +6 -20
  11. package/dist/merge-fields/dataProvenance.js.map +2 -2
  12. package/dist/merge-fields/index.js +1 -1
  13. package/dist/merge-fields/index.js.map +2 -2
  14. package/dist/merge-fields/mergableIndicator.js +1 -2
  15. package/dist/merge-fields/mergableIndicator.js.map +2 -2
  16. package/dist/merge-fields/mergeConfig.js +2 -0
  17. package/dist/merge-fields/mergeConfig.js.map +2 -2
  18. package/dist/merge-fields/mergeConstraints.js +35 -32
  19. package/dist/merge-fields/mergeConstraints.js.map +3 -3
  20. package/dist/merge-fields/mergeField.js +4 -3
  21. package/dist/merge-fields/mergeField.js.map +2 -2
  22. package/dist/merge-fields/mergeOrAddSubfield.js +8 -7
  23. package/dist/merge-fields/mergeOrAddSubfield.js.map +2 -2
  24. package/dist/merge-fields/mergeSubfield.js +5 -1
  25. package/dist/merge-fields/mergeSubfield.js.map +2 -2
  26. package/dist/merge-fields/worldKnowledge.js +52 -0
  27. package/dist/merge-fields/worldKnowledge.js.map +2 -2
  28. package/dist/merge-fields.test.js +2 -2
  29. package/dist/merge-fields.test.js.map +2 -2
  30. package/dist/normalize-dashes.js +2 -2
  31. package/dist/normalize-dashes.js.map +2 -2
  32. package/dist/normalizeFieldForComparison.js +8 -14
  33. package/dist/normalizeFieldForComparison.js.map +2 -2
  34. package/dist/prepublicationUtils.js +1 -1
  35. package/dist/prepublicationUtils.js.map +2 -2
  36. package/dist/punctuation2.js +10 -10
  37. package/dist/punctuation2.js.map +2 -2
  38. package/dist/removeDuplicateDataFields.js +1 -24
  39. package/dist/removeDuplicateDataFields.js.map +2 -2
  40. package/dist/removeInferiorDataFields.js +3 -2
  41. package/dist/removeInferiorDataFields.js.map +2 -2
  42. package/dist/sortSubfields.js +19 -19
  43. package/dist/sortSubfields.js.map +2 -2
  44. package/dist/subfield6Utils.js +0 -1
  45. package/dist/subfield6Utils.js.map +2 -2
  46. package/dist/subfield8Utils.js +0 -5
  47. package/dist/subfield8Utils.js.map +2 -2
  48. package/dist/utils.js +29 -3
  49. package/dist/utils.js.map +2 -2
  50. package/package.json +4 -4
  51. package/src/cyrillux.js +11 -11
  52. package/src/dataProvenanceUtils.js +21 -0
  53. package/src/index.js +3 -1
  54. package/src/merge-fields/controlSubfields.js +0 -1
  55. package/src/merge-fields/counterpartField.js +191 -290
  56. package/src/merge-fields/dataProvenance.js +8 -25
  57. package/src/merge-fields/index.js +1 -1
  58. package/src/merge-fields/mergableIndicator.js +1 -2
  59. package/src/merge-fields/mergeConfig.js +2 -1
  60. package/src/merge-fields/mergeConstraints.js +39 -34
  61. package/src/merge-fields/mergeField.js +4 -7
  62. package/src/merge-fields/mergeOrAddSubfield.js +8 -7
  63. package/src/merge-fields/mergeSubfield.js +11 -2
  64. package/src/merge-fields/worldKnowledge.js +72 -3
  65. package/src/merge-fields.test.js +2 -2
  66. package/src/normalize-dashes.js +2 -2
  67. package/src/normalizeFieldForComparison.js +19 -20
  68. package/src/prepublicationUtils.js +1 -1
  69. package/src/punctuation2.js +10 -10
  70. package/src/removeDuplicateDataFields.js +24 -24
  71. package/src/removeInferiorDataFields.js +3 -2
  72. package/src/sortSubfields.js +19 -19
  73. package/src/subfield6Utils.js +1 -1
  74. package/src/subfield8Utils.js +5 -5
  75. package/src/utils.js +39 -12
  76. package/test-fixtures/cyrillux/f14/expectedResult.json +32 -0
  77. package/test-fixtures/cyrillux/f14/metadata.json +10 -0
  78. package/test-fixtures/cyrillux/f14/record.json +14 -0
  79. package/test-fixtures/merge-fields/f042_01/expectedResult.json +12 -0
  80. package/test-fixtures/merge-fields/f042_01/metadata.json +6 -0
  81. package/test-fixtures/merge-fields/f042_01/record.json +13 -0
  82. package/test-fixtures/merge-fields/f06/expectedResult.json +42 -0
  83. package/test-fixtures/merge-fields/f06/metadata.json +6 -0
  84. package/test-fixtures/merge-fields/f06/record.json +41 -0
  85. package/test-fixtures/merge-fields/f07/expectedResult.json +18 -0
  86. package/test-fixtures/merge-fields/f07/metadata.json +6 -0
  87. package/test-fixtures/merge-fields/f07/record.json +18 -0
  88. package/test-fixtures/merge-fields/f08/expectedResult.json +12 -0
  89. package/test-fixtures/merge-fields/f08/metadata.json +7 -0
  90. package/test-fixtures/merge-fields/f08/record.json +10 -0
  91. package/test-fixtures/merge-fields/f09/expectedResult.json +14 -0
  92. package/test-fixtures/merge-fields/f09/metadata.json +6 -0
  93. package/test-fixtures/merge-fields/f09/record.json +14 -0
  94. package/test-fixtures/merge-fields/f10/expectedResult.json +25 -0
  95. package/test-fixtures/merge-fields/f10/metadata.json +6 -0
  96. package/test-fixtures/merge-fields/f10/record.json +25 -0
  97. package/test-fixtures/merge-fields/f11/expectedResult.json +40 -0
  98. package/test-fixtures/merge-fields/f11/metadata.json +7 -0
  99. package/test-fixtures/merge-fields/f11/record.json +50 -0
  100. package/test-fixtures/merge-fields/f12/expectedResult.json +17 -0
  101. package/test-fixtures/merge-fields/f12/metadata.json +6 -0
  102. package/test-fixtures/merge-fields/f12/record.json +25 -0
  103. package/test-fixtures/merge-fields/f13/expectedResult.json +18 -0
  104. package/test-fixtures/merge-fields/f13/metadata.json +6 -0
  105. package/test-fixtures/merge-fields/f13/record.json +28 -0
  106. package/test-fixtures/merge-fields/f14/expectedResult.json +25 -0
  107. package/test-fixtures/merge-fields/f14/metadata.json +6 -0
  108. package/test-fixtures/merge-fields/f14/record.json +25 -0
  109. package/test-fixtures/merge-fields/f300_01/expectedResult.json +9 -0
  110. package/test-fixtures/merge-fields/f300_01/metadata.json +6 -0
  111. package/test-fixtures/merge-fields/f300_01/record.json +8 -0
  112. package/test-fixtures/merge-fields/f300_02/expectedResult.json +13 -0
  113. package/test-fixtures/merge-fields/f300_02/metadata.json +6 -0
  114. package/test-fixtures/merge-fields/f300_02/record.json +16 -0
  115. package/test-fixtures/merge-fields/f490_01/expectedResult.json +13 -0
  116. package/test-fixtures/merge-fields/f490_01/metadata.json +6 -0
  117. package/test-fixtures/merge-fields/f490_01/record.json +16 -0
  118. package/test-fixtures/remove-inferior-datafields/f17/expectedResult.json +11 -0
  119. package/test-fixtures/remove-inferior-datafields/f17/metadata.json +5 -0
  120. package/test-fixtures/remove-inferior-datafields/f17/record.json +15 -0
@@ -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} from '../utils.js';\nimport {cloneAndNormalizeFieldForComparison, cloneAndRemovePunctuation} from '../normalizeFieldForComparison.js';\n// This should be done via our own normalizer:\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 {normalizeForSamenessCheck, valueCarriesMeaning} from './worldKnowledge.js';\nimport { provenanceSubfieldsPermitMerge } from './dataProvenance.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:mergeField:counterpart');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst irrelevantSubfieldsInNameAndTitlePartComparison = '5689';\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/*\nfunction differentPublisherSubfields(field1, field2) {\n if (field1.tag === '260' && field2.tag === '264' && field2.ind2 === '3') {\n return true;\n }\n if (field1.tag === '264' && field1.ind2 === '3' && field2.tag === '260') {\n return true;\n }\n return false;\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\nexport function 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 newer want there to repeat (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 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\n}\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 /*\n function isKustantaja(nameData) {\n if (nameData.suffix.match(/^(?:Kustannus|Kustannus oy|kustannusosakeyhti\u00F6)$/iu)) {\n return true;\n }\n if (nameData.prefix.match(/^Kustannus Oy$/i)) {\n return true;\n }\n return false;\n }\n */\n}\n\n\nfunction pairableValue(tag, subfieldCode, value1, value2) {\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 value1;\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 value1;\n }\n\n return undefined;\n}\n\n\nfunction counterpartExtraNormalize(tag, subfieldCode, value) {\n\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 value = removeCopyright(value);\n\n value = value.replace(/http:\\/\\//ug, 'https://'); // MET-501: http vs https\n value = normalizeForSamenessCheck(tag, subfieldCode, value);\n\n return value;\n}\n\nfunction uniqueKeyMatches(baseField, sourceField, forcedKeyString = null) {\n // NB! Assume that field1 and field2 have same relevant subfields.\n // What to do if if base\n // const keySubfieldsAsString = forcedKeyString || getUniqueKeyFields(field1);\n const keySubfieldsAsString = forcedKeyString || getMergeConstraintsForTag(baseField.tag, 'key');\n //return mandatorySubfieldComparison(baseField, sourceField, keySubfieldsAsString);\n return optionalSubfieldComparison(baseField, sourceField, keySubfieldsAsString);\n}\n\n\nfunction optionalSubfieldComparison(originalBaseField, originalSourceField, keySubfieldsAsString) {\n // Here \"optional subfield\" means a subfield, that needs not to be present, but if present, it must be identical...\n // (Think of a better name...)\n // We use clones here, since these changes done below are not intented to appear on the actual records.\n const field1 = cloneAndNormalizeFieldForComparison(originalBaseField);\n const field2 = cloneAndNormalizeFieldForComparison(originalSourceField);\n\n if (keySubfieldsAsString === null) { // does not currently happen\n // If keySubfieldsAsString is undefined, (practically) everything is the string.\n // When everything is the string, the strings need to be (practically) identical.\n // (NB! Here order matters. We should probably make it matter everywhere.)\n // (However, keySubfieldsAsString === '' will always succeed. Used by 040 at least.)\n // NB! substring(6) skips \"TAG II\" (I=indicator. Thus we skip indicators)\n return fieldToString(field1).substring(6) === fieldToString(field2).substring(6);\n }\n const subfieldArray = keySubfieldsAsString.split('');\n\n // 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 (subfieldArray.length > 0 && !subfieldArray.some(sfCode => hasCommonNominator(sfCode))) {\n return false;\n }\n\n\n return subfieldArray.every(subfieldCode => testOptionalSubfield(originalBaseField.tag, subfieldCode));\n\n\n function hasCommonNominator(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\n function testOptionalSubfield(tag, subfieldCode) {\n // NB! Don't compare non-meaningful subfields\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 // If one side is empty, all is good\n if (subfields1.length === 0 || subfields2.length === 0) {\n return true;\n }\n\n //nvdebugSubfieldArray(subfields1, 'SF1', debugDev);\n //nvdebugSubfieldArray(subfields2, 'SF2', debugDev);\n\n // When pairing we can use stronger normalizations than the generic one:\n const subfieldValues1 = subfields1.map(sf => counterpartExtraNormalize(tag, subfieldCode, sf.value));\n const subfieldValues2 = subfields2.map(sf => counterpartExtraNormalize(tag, subfieldCode, sf.value));\n\n //nvdebug(`SF1 NORM: ${subfieldValues1.join(' --')}`, debugDev);\n //nvdebug(`SF2 NORM: ${subfieldValues2.join(' --')}`, debugDev);\n\n // If one set is a subset of the other, all is probably good (how about 653$a, 505...)\n if (subfieldValues1.every(val => subfieldValues2.includes(val)) || subfieldValues2.every(val => subfieldValues1.includes(val))) {\n return true;\n }\n\n if (subfieldValues1.length === 1 && subfieldValues2.length === 1) {\n return pairableValue(field1.tag, subfieldCode, subfieldValues1[0], subfieldValues2[0]) !== undefined;\n }\n\n return false;\n\n }\n}\n\n\nfunction mandatorySubfieldComparison(originalField1, originalField2, keySubfieldsAsString) {\n // NB! We use clones here, since these changes done below are not intented to appear on the actual records.\n const field1 = cloneAndNormalizeFieldForComparison(originalField1);\n const field2 = cloneAndNormalizeFieldForComparison(originalField2);\n if (keySubfieldsAsString === null) { // does not currently happen\n // If keySubfieldsAsString is undefined, (practically) everything is the string.\n // When everything is the string, the strings need to be (practically) identical.\n // (NB! Here order matters. We should probably make it matter everywhere.)\n // (However, keySubfieldsAsString === '' will always succeed. Used by 040 at least.)\n return fieldToString(field1) === fieldToString(field2);\n }\n const subfieldArray = keySubfieldsAsString.split('');\n\n //const differentSubfieldCodes = differentPublisherSubfields(originalField1, originalField2);\n\n return subfieldArray.every(subfieldCode => mandatorySingleSubfieldComparison(subfieldCode));\n\n function mandatorySingleSubfieldComparison(subfieldCode) {\n //const otherSubfieldCode = getOtherSubfieldCode(subfieldCode);\n const subfieldValues1 = field1.subfields.filter(subfield => subfield.code === subfieldCode).map(sf => sf.value);\n const subfieldValues2 = field2.subfields.filter(subfield => subfield.code === subfieldCode).map(sf => sf.value);\n // Assume that at least 1 instance must exist and that all instances must match\n if (subfieldValues1.length !== subfieldValues2.length) {\n debugDev(`mSC: Unique key: subfield ${subfieldCode} issues...`);\n return false;\n }\n\n return subfieldValues1.every(value => subfieldValues2.includes(value));\n }\n\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');\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 arePairedSubfieldsInBalance(field1, field2) {\n const subfieldString = getMergeConstraintsForTag(field1.tag, 'paired');\n if (subfieldString === null) {\n return true;\n }\n const subfieldArray = subfieldString.split('');\n\n return subfieldArray.every(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 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 if (!arePairedSubfieldsInBalance(baseField, sourceField)) {\n nvdebug('required subfield pair check failed.', debugDev);\n return false;\n }\n\n return true;\n}\n\nfunction mergablePair(baseField, sourceField, config) {\n if (!syntacticallyMergablePair(baseField, sourceField, config)) {\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\n\nfunction pairableAsteriIDs(baseField, sourceField) {\n //nvdebug(`ASTERI1 ${fieldToString(baseField)}`, debugDev); // eslint-disable-line\n //nvdebug(`ASTERI2 ${fieldToString(sourceField)}`, debugDev); // eslint-disable-line\n\n // Check that relevant control subfield(s) exist in both records (as controlSubfieldsPermitMerge() doesn't check it):\n const fin11a = getAsteriIDs(baseField);\n if (fin11a.length === 0) {\n return false;\n }\n const fin11b = getAsteriIDs(sourceField);\n if (fin11b.length === 0) {\n return false;\n }\n //nvdebug(`ASTERI WP3:\\n${fin11a.join(\", \")}\\n${fin11b.join(\", \")}`, debugDev); // eslint-disable-line\n\n // Check that found control subfields agree. Use pre-existing generic function to reduce code.\n // (NB! We could optimize and just return true here, as control subfield check is done elsewhere as well.\n // However, explicitly checking them here makes the code more robust.)\n if (!controlSubfieldsPermitMerge(baseField, sourceField)) {\n return false;\n }\n //console.log(`ASTERI PAIR ${fieldToString(sourceField)}`); // eslint-disable-line\n return true;\n\n // NB! This boldly assumes that the default prefix for Asteri is '(FIN11)', not '(FI-ASTERI-N)' nor a finaf urn...\n function getAsteriIDs(field) {\n return field.subfields.filter(sf => sf.code === '0')\n .map(sf => normalizeControlSubfieldValue(sf.value))\n .filter(val => val.substring(0, 7) === '(FIN11)');\n }\n}\n\n\nfunction hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field) {\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 pairableName(baseField, sourceField) {\n // 100$a$t: remove $t and everything after that\n const reducedField1 = fieldToNamePart(baseField);\n const reducedField2 = fieldToNamePart(sourceField);\n\n const string1 = fieldToString(reducedField1);\n const string2 = fieldToString(reducedField2);\n\n //nvdebug(`IN: pairableName():\\n '${string1}' vs\\n '${string2}'`, debugDev);\n if (string1 === string2) {\n return true;\n }\n\n // Essentially these are too hard to handle with field-merge (eg. multi-505$g)\n if (hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(reducedField1) || hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(reducedField2)) {\n return false;\n }\n\n // Compare the remaining subsets...\n // First check that name matches...\n if (uniqueKeyMatches(reducedField1, reducedField2)) {\n nvdebug(` name match: '${fieldToString(reducedField1)}'`, debugDev);\n return true;\n }\n\n // However, name mismatch is not critical! If Asteri ID matches, it's still a match! *NOT* sure whether this a good idea.\n // 2023-01-24 Disable this. Caretaker can fix these later on. Not a job for merge. We can't be sure that $0 pair is corrent, nor which version (base or source) to use.\n // 2023-03-07: Enable this again!\n if (pairableAsteriIDs(baseField, sourceField)) {\n //nvdebug(` name match based on ASTERI $0'`, debugDev);\n return true;\n }\n\n nvdebug(` name mismatch:`, debugDev);\n nvdebug(` '${fieldToString(reducedField1)}' vs`, debugDev);\n nvdebug(` '${fieldToString(reducedField2)}'`, debugDev);\n return false;\n}\n\n\nfunction semanticallyMergablePair(baseField, sourceField) {\n // On rare occasions a field contains also a title part. For these name part (= normally everything) and title part\n // must be checked separately:\n if (!titlePartsMatch(baseField, sourceField)) {\n nvdebug(` ${baseField.tag} is unmergable: Title part mismatch.`, debugDev);\n return false;\n }\n\n // Hmm... we should check lifespan here, $d YYYY\n\n // Handle the field specific \"unique key\" (=set of fields that make the field unique\n if (!pairableName(baseField, sourceField)) {\n nvdebug('Unmergable: Name part mismatch', debugDev);\n return false;\n }\n //debug(' Semantic checks passed! We are MERGABLE!');\n\n return true;\n}\n\n\nfunction namePartThreshold(field) {\n // Threshold is only applicaple to some tags..\n if (!(/[10]0$/u).test(field.tag)) {\n return -1;\n }\n const t = field.subfields.findIndex(currSubfield => currSubfield.code === 't');\n const u = t; // field.subfields.findIndex(currSubfield => currSubfield.code === 'u');\n if (t === -1) {\n return u;\n }\n if (u === -1) {\n return t;\n }\n return t > u ? u : t;\n}\n\nfunction fieldToNamePart(field) {\n const index = namePartThreshold(field);\n const relevantSubfields = field.subfields.filter((sf, i) => i < index || index === -1).filter(sf => !irrelevantSubfieldsInNameAndTitlePartComparison.includes(sf.code));\n\n const subsetField = {'tag': field.tag, 'ind1': field.ind1, 'ind2': field.ind2, subfields: relevantSubfields};\n\n /*\n if (index > -1) {\n debugDev(`Name subset: ${fieldToString(subsetField)}`);\n }\n */\n\n // Ummm... Sometimes $0 comes after $t but belongs to name part\n\n return subsetField;\n}\n\nfunction fieldToTitlePart(field) {\n // Take everything after 1st subfield $t...\n const index = field.subfields.findIndex(currSubfield => currSubfield.code === 't');\n const relevantSubfields = field.subfields.filter((sf, i) => i >= index).filter(sf => !irrelevantSubfieldsInNameAndTitlePartComparison.includes(sf.code));\n const subsetField = {'tag': field.tag, 'ind1': field.ind1, 'ind2': field.ind2, subfields: relevantSubfields};\n debugDev(`Title subset: ${fieldToString(subsetField)}`);\n return subsetField;\n}\n\nfunction containsTitlePart(field) {\n return fieldCanHaveTitlePart(field) && fieldHasSubfield(field, 't');\n\n function fieldCanHaveTitlePart(field) {\n return ['100', '110', '111', '700', '710', '711'].includes(field.tag);\n }\n}\n\nfunction titlePartsMatch(field1, field2) {\n if (!containsTitlePart(field1)) {\n return !containsTitlePart(field2);\n }\n if (!containsTitlePart(field2)) {\n return false;\n }\n\n debugDev(`TITLE PARTS NEED TO BE COMPARED`);\n\n // 100$a$t: remove $t and everything after that\n const subset1 = fieldToTitlePart(field1);\n const subset2 = fieldToTitlePart(field2);\n // Easter Egg, ffs. Hardcoded exception\n return mandatorySubfieldComparison(subset1, subset2, 'dfhklmnoprstxvg');\n}\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 nvdebug('Field 264 exception as per MET-456', debugDev);\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 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(`Norm to: '${fieldToString(normalizedField)}'`, debugDev);\n\n const uniqueAlternativeNames = getUniqueAlernativeNames();\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 //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\n"],
5
- "mappings": "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",
6
- "names": ["suffix", "prefix", "name", "field"]
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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",
6
+ "names": ["suffix", "prefix", "name", "tag", "field"]
7
7
  }
@@ -1,29 +1,15 @@
1
1
  import { subfieldArraysContainSameData } from "../utils.js";
2
- export function tagToDataProvenanceSubfieldCode(tag) {
3
- if (["533", "800", "810", "811", "830"].includes(tag)) {
4
- return "y";
5
- }
6
- if (tag === "856" || tag === "857") {
7
- return "e";
8
- }
9
- if (tag.match(/^7[678]/u)) {
10
- return "l";
11
- }
12
- if (tag.match(/^00/u)) {
13
- return void 0;
14
- }
15
- return "7";
16
- }
2
+ import { tagToDataProvenanceSubfieldCode } from "../dataProvenanceUtils.js";
17
3
  export function provenanceSubfieldsPermitMerge(baseField, sourceField) {
18
- const provinanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);
19
4
  if (!baseField.subfields) {
20
5
  return true;
21
6
  }
22
- if (provinanceSubfieldCode === void 0) {
7
+ const provenanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);
8
+ if (provenanceSubfieldCode === void 0) {
23
9
  return false;
24
10
  }
25
- const baseProvinanceSubfields = baseField.subfields.filter((sf) => sf.code === provinanceSubfieldCode);
26
- const sourceProvinanceSubfields = sourceField.subfields.filter((sf) => sf.code === provinanceSubfieldCode);
27
- return subfieldArraysContainSameData(baseProvinanceSubfields, sourceProvinanceSubfields);
11
+ const baseProvenanceSubfields = baseField.subfields.filter((sf) => sf.code === provenanceSubfieldCode);
12
+ const sourceProvenanceSubfields = sourceField.subfields.filter((sf) => sf.code === provenanceSubfieldCode);
13
+ return subfieldArraysContainSameData(baseProvenanceSubfields, sourceProvenanceSubfields);
28
14
  }
29
15
  //# sourceMappingURL=dataProvenance.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/merge-fields/dataProvenance.js"],
4
- "sourcesContent": ["// See https://www.loc.gov/marc/bibliographic/bdapndxj.html for details\n\nimport {subfieldArraysContainSameData} from \"../utils.js\";\n\nexport function tagToDataProvenanceSubfieldCode(tag) {\n if ( ['533', '800', '810', '811', '830'].includes(tag)) {\n return 'y';\n }\n if ( tag === '856' || tag === '857' ) {\n return 'e';\n }\n\n if ( tag.match(/^7[678]/u) ) {\n return 'l'\n }\n\n if ( tag.match(/^00/u)) {\n return undefined;\n }\n return '7';\n}\n\n\nexport function provenanceSubfieldsPermitMerge(baseField, sourceField) {\n const provinanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);\n if (!baseField.subfields) {\n return true;\n }\n if (provinanceSubfieldCode === undefined) {\n return false;\n }\n\n const baseProvinanceSubfields = baseField.subfields.filter(sf => sf.code === provinanceSubfieldCode);\n const sourceProvinanceSubfields = sourceField.subfields.filter(sf => sf.code === provinanceSubfieldCode);\n\n // Currently we just compare two arrays. Later on we might do something more sophisticated with specific $7 data provenance category/relationship codes,\n // or actual values.\n\n return subfieldArraysContainSameData(baseProvinanceSubfields, sourceProvinanceSubfields);\n\n}"],
5
- "mappings": "AAEA,SAAQ,qCAAoC;AAErC,gBAAS,gCAAgC,KAAK;AACjD,MAAK,CAAC,OAAO,OAAO,OAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACpD,WAAO;AAAA,EACX;AACA,MAAK,QAAQ,SAAS,QAAQ,OAAQ;AAClC,WAAO;AAAA,EACX;AAEA,MAAK,IAAI,MAAM,UAAU,GAAI;AACzB,WAAO;AAAA,EACX;AAEA,MAAK,IAAI,MAAM,MAAM,GAAG;AACpB,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAGO,gBAAS,+BAA+B,WAAW,aAAa;AACnE,QAAM,yBAAyB,gCAAgC,UAAU,GAAG;AAC5E,MAAI,CAAC,UAAU,WAAW;AACtB,WAAO;AAAA,EACX;AACA,MAAI,2BAA2B,QAAW;AACtC,WAAO;AAAA,EACX;AAEA,QAAM,0BAA0B,UAAU,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AACnG,QAAM,4BAA4B,YAAY,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AAKvG,SAAO,8BAA8B,yBAAyB,yBAAyB;AAE3F;",
4
+ "sourcesContent": ["// See https://www.loc.gov/marc/bibliographic/bdapndxj.html for details\n\nimport {subfieldArraysContainSameData} from '../utils.js';\nimport {tagToDataProvenanceSubfieldCode} from '../dataProvenanceUtils.js';\n\nexport function provenanceSubfieldsPermitMerge(baseField, sourceField) {\n if (!baseField.subfields) {\n return true;\n }\n const provenanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);\n\n if (provenanceSubfieldCode === undefined) {\n return false;\n }\n\n const baseProvenanceSubfields = baseField.subfields.filter(sf => sf.code === provenanceSubfieldCode);\n const sourceProvenanceSubfields = sourceField.subfields.filter(sf => sf.code === provenanceSubfieldCode);\n\n // Currently we just compare two arrays. Later on we might do something more sophisticated with specific $7 data provenance category/relationship codes,\n // or actual values.\n\n return subfieldArraysContainSameData(baseProvenanceSubfields, sourceProvenanceSubfields);\n\n}"],
5
+ "mappings": "AAEA,SAAQ,qCAAoC;AAC5C,SAAQ,uCAAsC;AAEvC,gBAAS,+BAA+B,WAAW,aAAa;AACnE,MAAI,CAAC,UAAU,WAAW;AACtB,WAAO;AAAA,EACX;AACA,QAAM,yBAAyB,gCAAgC,UAAU,GAAG;AAE5E,MAAI,2BAA2B,QAAW;AACtC,WAAO;AAAA,EACX;AAEA,QAAM,0BAA0B,UAAU,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AACnG,QAAM,4BAA4B,YAAY,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AAKvG,SAAO,8BAA8B,yBAAyB,yBAAyB;AAE3F;",
6
6
  "names": []
7
7
  }
@@ -29,7 +29,7 @@ export default function(defaultTagPattern = void 0) {
29
29
  mergeFieldsWithinRecord(record, config);
30
30
  }
31
31
  function fix(record, config = void 0) {
32
- const config2 = config || defaultConfig;
32
+ const config2 = config || defaultConfig.mergeConfiguration;
33
33
  record.internalMerge = true;
34
34
  mergeFieldsWithinRecord(record, config2);
35
35
  delete record.internalMerge;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/merge-fields/index.js"],
4
- "sourcesContent": ["// NB! This validator is build on code that merged two different records originally in marc-record-merge-reducers.\n// The idea was to write a validator that can merge fields in one record. (This is a good idea at least for field tags /^[1678](00|10|11|30)$/.)\n// As we don't want copypaste coding everything was moved here, and marc-record-merge-reducers exports mergeField() function.\n// That function uses a lot of stuff that is meant for the two-record-merge case only. Thus the tests for this validator are pretty limited here,\n// and the test coverage is low. The extensive set of tests in in marc-record-merge-reducers for this code.\n\n\n//import createDebugLogger from 'debug';\n//import fs from 'fs';\n//import path from 'path';\nimport {mergeField} from './mergeField.js';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {postprocessRecords} from './mergeOrAddPostprocess.js';\n\nconst description = 'Merge fields within record';\n\nimport {mergeConfig as defaultConfig} from './mergeConfig.js';\n\n//const defaultConfig = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'src', 'merge-fields', 'config.json'), 'utf8'));\n\nexport default function (defaultTagPattern = undefined) {\n\n return {\n description, validate, fix\n };\n\n function getTagPattern(config) {\n if (config && config.tagPattern) {\n return config.tagPattern;\n }\n if (defaultTagPattern) { // Used by tests\n return defaultTagPattern;\n }\n return '^[1678](?:00|10|11|30)$';\n }\n\n function mergeFieldsWithinRecord(record, config) {\n //const candFields = record.fields.toReversed(); // Node 20+ only! Filter via config?\n const fields = record.get(getTagPattern(config)); // config && config.tagPattern ? record.get(config.tagPattern) : record.get(/^[1678](?:00|10|11|30)$/u);\n\n fields.reverse();\n const mergedField = fields.find(f => mergeField(record, record, f, config));\n if (!mergedField) {\n return;\n }\n record.removeField(mergedField);\n mergeFieldsWithinRecord(record, config);\n\n }\n\n function fix(record, config = undefined) {\n const config2 = config || defaultConfig;\n record.internalMerge = true;\n mergeFieldsWithinRecord(record, config2);\n delete record.internalMerge;\n // Remove deleted fields and field.merged marks:\n postprocessRecords(record, record);\n\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n function validate(record, config) {\n //nvdebug(`VALIDATE ${description}...`);\n\n const nFields = record.fields.length;\n const clonedRecord = new MarcRecord(record, {subfieldValues: false});\n fix(clonedRecord, config);\n\n const nFields2 = clonedRecord.fields.length;\n if (nFields === nFields2) {\n return {message: [], valid: true};\n }\n\n const msg = `${description}: number of fields changes from ${nFields} to ${nFields2}`;\n return {message: [msg], valid: false};\n }\n\n}\n\n"],
5
- "mappings": "AAUA,SAAQ,kBAAiB;AACzB,SAAQ,kBAAiB;AACzB,SAAQ,0BAAyB;AAEjC,MAAM,cAAc;AAEpB,SAAQ,eAAe,qBAAoB;AAI3C,wBAAyB,oBAAoB,QAAW;AAEtD,SAAO;AAAA,IACL;AAAA,IAAa;AAAA,IAAU;AAAA,EACzB;AAEA,WAAS,cAAc,QAAQ;AAC7B,QAAI,UAAU,OAAO,YAAY;AAC/B,aAAO,OAAO;AAAA,IAChB;AACA,QAAI,mBAAmB;AACrB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,WAAS,wBAAwB,QAAQ,QAAQ;AAE/C,UAAM,SAAS,OAAO,IAAI,cAAc,MAAM,CAAC;AAE/C,WAAO,QAAQ;AACf,UAAM,cAAc,OAAO,KAAK,OAAK,WAAW,QAAQ,QAAQ,GAAG,MAAM,CAAC;AAC1E,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AACA,WAAO,YAAY,WAAW;AAC9B,4BAAwB,QAAQ,MAAM;AAAA,EAExC;AAEA,WAAS,IAAI,QAAQ,SAAS,QAAW;AACvC,UAAM,UAAU,UAAU;AAC1B,WAAO,gBAAgB;AACvB,4BAAwB,QAAQ,OAAO;AACvC,WAAO,OAAO;AAEd,uBAAmB,QAAQ,MAAM;AAEjC,UAAM,MAAM,EAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,KAAI;AAC9C,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,QAAQ,QAAQ;AAGhC,UAAM,UAAU,OAAO,OAAO;AAC9B,UAAM,eAAe,IAAI,WAAW,QAAQ,EAAC,gBAAgB,MAAK,CAAC;AACnE,QAAI,cAAc,MAAM;AAExB,UAAM,WAAW,aAAa,OAAO;AACrC,QAAI,YAAY,UAAU;AACxB,aAAO,EAAC,SAAS,CAAC,GAAG,OAAO,KAAI;AAAA,IAClC;AAEA,UAAM,MAAM,GAAG,WAAW,mCAAmC,OAAO,OAAO,QAAQ;AACnF,WAAO,EAAC,SAAS,CAAC,GAAG,GAAG,OAAO,MAAK;AAAA,EACtC;AAEF;",
4
+ "sourcesContent": ["// NB! This validator is build on code that merged two different records originally in marc-record-merge-reducers.\n// The idea was to write a validator that can merge fields in one record. (This is a good idea at least for field tags /^[1678](00|10|11|30)$/.)\n// As we don't want copypaste coding everything was moved here, and marc-record-merge-reducers exports mergeField() function.\n// That function uses a lot of stuff that is meant for the two-record-merge case only. Thus the tests for this validator are pretty limited here,\n// and the test coverage is low. The extensive set of tests in in marc-record-merge-reducers for this code.\n\n\n//import createDebugLogger from 'debug';\n//import fs from 'fs';\n//import path from 'path';\nimport {mergeField} from './mergeField.js';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {postprocessRecords} from './mergeOrAddPostprocess.js';\n\nconst description = 'Merge fields within record';\n\nimport {mergeConfig as defaultConfig} from './mergeConfig.js';\n\n//const defaultConfig = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'src', 'merge-fields', 'config.json'), 'utf8'));\n\nexport default function (defaultTagPattern = undefined) {\n\n return {\n description, validate, fix\n };\n\n function getTagPattern(config) {\n if (config && config.tagPattern) {\n return config.tagPattern;\n }\n if (defaultTagPattern) { // Used by tests\n return defaultTagPattern;\n }\n return '^[1678](?:00|10|11|30)$';\n }\n\n function mergeFieldsWithinRecord(record, config) {\n //const candFields = record.fields.toReversed(); // Node 20+ only! Filter via config?\n const fields = record.get(getTagPattern(config)); // config && config.tagPattern ? record.get(config.tagPattern) : record.get(/^[1678](?:00|10|11|30)$/u);\n\n fields.reverse();\n const mergedField = fields.find(f => mergeField(record, record, f, config));\n if (!mergedField) {\n return;\n }\n record.removeField(mergedField);\n mergeFieldsWithinRecord(record, config);\n\n }\n\n function fix(record, config = undefined) {\n const config2 = config || defaultConfig.mergeConfiguration;\n record.internalMerge = true;\n mergeFieldsWithinRecord(record, config2);\n delete record.internalMerge;\n // Remove deleted fields and field.merged marks:\n postprocessRecords(record, record);\n\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n function validate(record, config) {\n //nvdebug(`VALIDATE ${description}...`);\n\n const nFields = record.fields.length;\n const clonedRecord = new MarcRecord(record, {subfieldValues: false});\n fix(clonedRecord, config);\n\n const nFields2 = clonedRecord.fields.length;\n if (nFields === nFields2) {\n return {message: [], valid: true};\n }\n\n const msg = `${description}: number of fields changes from ${nFields} to ${nFields2}`;\n return {message: [msg], valid: false};\n }\n\n}\n\n"],
5
+ "mappings": "AAUA,SAAQ,kBAAiB;AACzB,SAAQ,kBAAiB;AACzB,SAAQ,0BAAyB;AAEjC,MAAM,cAAc;AAEpB,SAAQ,eAAe,qBAAoB;AAI3C,wBAAyB,oBAAoB,QAAW;AAEtD,SAAO;AAAA,IACL;AAAA,IAAa;AAAA,IAAU;AAAA,EACzB;AAEA,WAAS,cAAc,QAAQ;AAC7B,QAAI,UAAU,OAAO,YAAY;AAC/B,aAAO,OAAO;AAAA,IAChB;AACA,QAAI,mBAAmB;AACrB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,WAAS,wBAAwB,QAAQ,QAAQ;AAE/C,UAAM,SAAS,OAAO,IAAI,cAAc,MAAM,CAAC;AAE/C,WAAO,QAAQ;AACf,UAAM,cAAc,OAAO,KAAK,OAAK,WAAW,QAAQ,QAAQ,GAAG,MAAM,CAAC;AAC1E,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AACA,WAAO,YAAY,WAAW;AAC9B,4BAAwB,QAAQ,MAAM;AAAA,EAExC;AAEA,WAAS,IAAI,QAAQ,SAAS,QAAW;AACvC,UAAM,UAAU,UAAU,cAAc;AACxC,WAAO,gBAAgB;AACvB,4BAAwB,QAAQ,OAAO;AACvC,WAAO,OAAO;AAEd,uBAAmB,QAAQ,MAAM;AAEjC,UAAM,MAAM,EAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,KAAI;AAC9C,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,QAAQ,QAAQ;AAGhC,UAAM,UAAU,OAAO,OAAO;AAC9B,UAAM,eAAe,IAAI,WAAW,QAAQ,EAAC,gBAAgB,MAAK,CAAC;AACnE,QAAI,cAAc,MAAM;AAExB,UAAM,WAAW,aAAa,OAAO;AACrC,QAAI,YAAY,UAAU;AACxB,aAAO,EAAC,SAAS,CAAC,GAAG,OAAO,KAAI;AAAA,IAClC;AAEA,UAAM,MAAM,GAAG,WAAW,mCAAmC,OAAO,OAAO,QAAQ;AACnF,WAAO,EAAC,SAAS,CAAC,GAAG,GAAG,OAAO,MAAK;AAAA,EACtC;AAEF;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import createDebugLogger from "debug";
2
- import { marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value, nvdebug } from "../utils.js";
2
+ import { marc21GetTagsLegalInd1Value, marc21GetTagsLegalInd2Value } from "../utils.js";
3
3
  const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator");
4
4
  const debugDev = debug.extend("dev");
5
5
  const ind1NonFilingChars = ["130", "630", "730", "740"];
@@ -13,7 +13,6 @@ function marc21NoNeedToCheckInd1(tag) {
13
13
  }
14
14
  function marc21NoNeedToCheckInd2(tag) {
15
15
  const cands = marc21GetTagsLegalInd2Value(tag);
16
- nvdebug(`CHECK IND2 ${typeof cands} FOR ${tag}`, debugDev);
17
16
  if (typeof cands === "string") {
18
17
  return true;
19
18
  }
@@ -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, nvdebug} from '../utils.js';\n\n// Specs: https://workgroups.helsinki.fi/x/K1ohCw (though we occasionally differ from them)...\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator');\n//const debugData = debug.extend('data');\nconst 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 nvdebug(`CHECK IND2 ${typeof cands} FOR ${tag}`, debugDev);\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": "AAAA,OAAO,uBAAuB;AAC9B,SAAQ,6BAA6B,6BAA6B,eAAc;AAIhF,MAAM,QAAQ,kBAAkB,yEAAyE;AAEzG,MAAM,WAAW,MAAM,OAAO,KAAK;AAEnC,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,UAAQ,cAAc,OAAO,KAAK,QAAQ,GAAG,IAAI,QAAQ;AACzD,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;",
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\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:merge-fields:mergableIndicator');\n//const debugData = debug.extend('data');\nconst 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": "AAAA,OAAO,uBAAuB;AAC9B,SAAQ,6BAA6B,mCAAkC;AAIvE,MAAM,QAAQ,kBAAkB,yEAAyE;AAEzG,MAAM,WAAW,MAAM,OAAO,KAAK;AAEnC,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
  }
@@ -31,8 +31,10 @@ export const mergeConfig = {
31
31
  "363": { "0": 1, "1": 1, " ": 2 },
32
32
  "382": { "0": 1, "1": 1, " ": 2 },
33
33
  "730": ["2", " "]
34
+ // If this is ok, it ok for 700, 710 and 711 as well...
34
35
  },
35
36
  "comment #4": "List indicators that do not block merge here. Non-filing indicators do not prevent field merge (their support is hard-coded). They are mainly listed here as an example.",
37
+ // Actually I wouldn't want to ignore X00ind1=3 vs other values such as IND1=1... However, this is not currently supported.
36
38
  "ignoreIndicator1": ["100", "110", "111", "130", "210", "242", "245", "246", "247", "307", "490", "505", "506", "510", "511", "516", "520", "521", "522", "524", "526", "583", "586", "600", "610", "630", "650", "651", "655", "700", "710", "730", "740", "760", "762", "765", "767", "770", "772", "773", "774", "775", "776", "777", "780", "785", "786", "787", "788", "800", "810"],
37
39
  "ignoreIndicator2": ["017", "222", "240", "242", "243", "245", "760", "762", "765", "767", "770", "773", "774", "775", "776", "777", "786", "787", "788", "830"],
38
40
  "comment #5": "If one indicator has value, and the other has not, it does not necessarily mean mismatch",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/merge-fields/mergeConfig.js"],
4
- "sourcesContent": ["export const mergeConfig = {\n 'mergeConfiguration': {\n 'comment #1': 'Meaningless indicators (=indicators having but one legal value) are derived from melindaCustomMergeFields.',\n 'comment #2': 'Meaningless indicators and non-filing indicators never prevent merge. (Hard-coded in mergableIndicator.js)',\n 'comment #3': 'When merging, indicator preference defaults are defined in mergeIndicators.js. However, these can be overridden here.',\n 'indicator1PreferredValues': {\n '022': {'0': 1, '1': 1, ' ': 2},\n '041': {'0': 1, '1': 1, ' ': 2},\n '246': {'0': 1, '1': 1, '2': 1, '3': 1, ' ': 2},\n '341': {'0': 1, '1': 1, ' ': 2},\n '363': {'0': 1, '1': 1, ' ': 2},\n '382': {'0': 1, '1': 1, '2': 1, '3': 1, ' ': 2},\n '384': {'0': 1, '1': 1, ' ': 2},\n '388': {'0': 1, '1': 1, ' ': 2},\n '490': ['1', '0'],\n '505': ['8', '0', '2', '1'],\n '506': {'0': 1, '1': 1, ' ': 2},\n '541': {'0': 1, '1': 1, ' ': 2},\n '542': {'0': 1, '1': 1, ' ': 2},\n '544': {'0': 1, '1': 1, ' ': 2},\n '545': {'0': 1, '1': 1, ' ': 2},\n '561': {'0': 1, '1': 1, ' ': 2},\n '583': {'0': 1, '1': 1, ' ': 2},\n '588': {'0': 1, '1': 1, ' ': 2},\n '650': [' ', '1', '2', '0']\n },\n 'indicator2PreferredValues': {\n '024': {'0': 1, '1': 1, ' ': 2},\n '033': {'0': 1, '1': 1, '2': 1, ' ': 2},\n '246': {'0': 1, '1': 1, '2': 1, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1, '8': 1, ' ': 2},\n '363': {'0': 1, '1': 1, ' ': 2},\n '382': {'0': 1, '1': 1, ' ': 2},\n '730': ['2', ' ']\n },\n 'comment #4': 'List indicators that do not block merge here. Non-filing indicators do not prevent field merge (their support is hard-coded). They are mainly listed here as an example.',\n 'ignoreIndicator1': ['100', '110', '111', '130', '210', '242', '245', '246', '247', '307', '490', '505', '506', '510', '511', '516', '520', '521', '522', '524', '526', '583', '586', '600', '610', '630', '650', '651', '655', '700', '710', '730', '740', '760', '762', '765', '767', '770', '772', '773', '774', '775', '776', '777', '780', '785', '786', '787', '788', '800', '810'],\n 'ignoreIndicator2': ['017', '222', '240', '242', '243', '245', '760', '762', '765', '767', '770', '773', '774', '775', '776', '777', '786', '787', '788', '830'],\n 'comment #5': 'If one indicator has value, and the other has not, it does not necessarily mean mismatch',\n 'tolerateBlankIndicator1': ['022', '037', '041', '046', '050', '055', '060', '070', '080', '246', '260', '264', '341', '363', '382', '384', '388', '541', '542', '544', '545', '561', '583', '588', '856'],\n 'tolerateBlankIndicator2': ['024', '033', '082', '246', '363', '382', '856'],\n 'preprocessorDirectives': [\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '100'},\n 'comment': 'NB! Retags should check corresponding 880 fields as well.',\n 'newTag': '700'\n },\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '110'},\n 'newTag': '710'\n },\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '111'},\n 'newTag': '711'\n },\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '130'},\n 'newTag': '730'\n }\n ]\n }\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export const mergeConfig = {\n 'mergeConfiguration': {\n 'comment #1': 'Meaningless indicators (=indicators having but one legal value) are derived from melindaCustomMergeFields.',\n 'comment #2': 'Meaningless indicators and non-filing indicators never prevent merge. (Hard-coded in mergableIndicator.js)',\n 'comment #3': 'When merging, indicator preference defaults are defined in mergeIndicators.js. However, these can be overridden here.',\n 'indicator1PreferredValues': {\n '022': {'0': 1, '1': 1, ' ': 2},\n '041': {'0': 1, '1': 1, ' ': 2},\n '246': {'0': 1, '1': 1, '2': 1, '3': 1, ' ': 2},\n '341': {'0': 1, '1': 1, ' ': 2},\n '363': {'0': 1, '1': 1, ' ': 2},\n '382': {'0': 1, '1': 1, '2': 1, '3': 1, ' ': 2},\n '384': {'0': 1, '1': 1, ' ': 2},\n '388': {'0': 1, '1': 1, ' ': 2},\n '490': ['1', '0'],\n '505': ['8', '0', '2', '1'],\n '506': {'0': 1, '1': 1, ' ': 2},\n '541': {'0': 1, '1': 1, ' ': 2},\n '542': {'0': 1, '1': 1, ' ': 2},\n '544': {'0': 1, '1': 1, ' ': 2},\n '545': {'0': 1, '1': 1, ' ': 2},\n '561': {'0': 1, '1': 1, ' ': 2},\n '583': {'0': 1, '1': 1, ' ': 2},\n '588': {'0': 1, '1': 1, ' ': 2},\n '650': [' ', '1', '2', '0']\n },\n 'indicator2PreferredValues': {\n '024': {'0': 1, '1': 1, ' ': 2},\n '033': {'0': 1, '1': 1, '2': 1, ' ': 2},\n '246': {'0': 1, '1': 1, '2': 1, '3': 1, '4': 1, '5': 1, '6': 1, '7': 1, '8': 1, ' ': 2},\n '363': {'0': 1, '1': 1, ' ': 2},\n '382': {'0': 1, '1': 1, ' ': 2},\n '730': ['2', ' '] // If this is ok, it ok for 700, 710 and 711 as well...\n },\n 'comment #4': 'List indicators that do not block merge here. Non-filing indicators do not prevent field merge (their support is hard-coded). They are mainly listed here as an example.',\n // Actually I wouldn't want to ignore X00ind1=3 vs other values such as IND1=1... However, this is not currently supported.\n 'ignoreIndicator1': ['100', '110', '111', '130', '210', '242', '245', '246', '247', '307', '490', '505', '506', '510', '511', '516', '520', '521', '522', '524', '526', '583', '586', '600', '610', '630', '650', '651', '655', '700', '710', '730', '740', '760', '762', '765', '767', '770', '772', '773', '774', '775', '776', '777', '780', '785', '786', '787', '788', '800', '810'],\n 'ignoreIndicator2': ['017', '222', '240', '242', '243', '245', '760', '762', '765', '767', '770', '773', '774', '775', '776', '777', '786', '787', '788', '830'],\n 'comment #5': 'If one indicator has value, and the other has not, it does not necessarily mean mismatch',\n 'tolerateBlankIndicator1': ['022', '037', '041', '046', '050', '055', '060', '070', '080', '246', '260', '264', '341', '363', '382', '384', '388', '541', '542', '544', '545', '561', '583', '588', '856'],\n 'tolerateBlankIndicator2': ['024', '033', '082', '246', '363', '382', '856'],\n 'preprocessorDirectives': [\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '100'},\n 'comment': 'NB! Retags should check corresponding 880 fields as well.',\n 'newTag': '700'\n },\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '110'},\n 'newTag': '710'\n },\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '111'},\n 'newTag': '711'\n },\n {\n 'operation': 'retag',\n 'recordType': 'source',\n 'fieldSpecification': {'tag': '130'},\n 'newTag': '730'\n }\n ]\n }\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,11 @@
1
1
  import createDebugLogger from "debug";
2
2
  const debug = createDebugLogger("@natlibfi/melinda-marc-record-merge-reducers:mergeConstraints");
3
3
  const debugDev = debug.extend("dev");
4
- const keyX00 = "abcjloqrtuwx";
5
- const keyX10 = "abcdfghlnoprstuwx";
6
- const keyX11 = "acdefghlnpqstuwx";
4
+ const keyX00 = "abcjklnoqrstuwx";
5
+ const keyX10 = "abcdfghklnoprstuwx";
6
+ const keyX11 = "acdefghklnpqstuwx";
7
7
  const keyX30 = "adfghklmnoprstvwxyz";
8
+ const pairedTitleSubfields = "iklmnoprst";
8
9
  const mergeConstraints = [
9
10
  { "tag": "010", "required": "a", "key": "a" },
10
11
  { "tag": "013", "required": "a", "key": "a" },
@@ -34,10 +35,10 @@ const mergeConstraints = [
34
35
  { "tag": "037", "required": "b", "key": "ab" },
35
36
  { "tag": "039", "required": "a" },
36
37
  { "tag": "040", "required": "", "key": "" },
37
- { "tag": "041", "required": "", "paired": "2", "key": "" },
38
+ { "tag": "041", "required": "", "paired": "2", "key": "ad" },
38
39
  // Don't put $2 in 'key'! hasCommonNominator() would get into trouble with it...
39
- { "tag": "042", "required": "a", "key": "" },
40
- // NB: preprocessor hacks applied
40
+ { "tag": "042", "required": "", "key": "" },
41
+ // Contents (supposedly $a subfields) can be anything, and still merge... (042 $a foo + 042 $b bar is perfectly mergeable)
41
42
  { "tag": "043", "required": "a", "key": "abc" },
42
43
  { "tag": "044", "required": "", "key": "abc", "paired": "abc" },
43
44
  { "tag": "045", "required": "", "key": "abc", "paired": "abc" },
@@ -67,11 +68,11 @@ const mergeConstraints = [
67
68
  { "tag": "086", "required": "", "paired": "a", "key": "a" },
68
69
  { "tag": "088", "required": "", "paired": "a", "key": "a" },
69
70
  // NB! 100, 110 and 111 may have title parts that are handled elsewhere
70
- { "tag": "100", "required": "a", "paired": "t", "key": keyX00 },
71
- { "tag": "110", "required": "a", "paired": "bt", "key": keyX10 },
72
- { "tag": "111", "required": "a", "paired": "t", "key": keyX11 },
71
+ { "tag": "100", "required": "a", "paired": `b${pairedTitleSubfields}`, "key": keyX00 },
72
+ { "tag": "110", "required": "a", "paired": `b${pairedTitleSubfields}`, "key": keyX10 },
73
+ { "tag": "111", "required": "a", "paired": pairedTitleSubfields, "key": keyX11 },
73
74
  // NB! 130 has no name part, key is used for title part
74
- { "tag": "130", "required": "a", "key": keyX30 },
75
+ { "tag": "130", "required": "a", paired: pairedTitleSubfields, "key": keyX30 },
75
76
  { "tag": "210", "required": "a", "key": "ab" },
76
77
  { "tag": "222", "required": "a", "key": "ab" },
77
78
  { "tag": "240", "required": "a", "key": "adfghklmnoprs" },
@@ -95,7 +96,7 @@ const mergeConstraints = [
95
96
  { "tag": "264", "required": "", "key": "abc" },
96
97
  // NB "S.l." normalizations?" not implemented
97
98
  // SKIP TAG 270 ON PURPOSE! Melinda's N=43.
98
- { "tag": "300", "required": "a", "key": "abcefg" },
99
+ { "tag": "300", "required": "", "key": "abcefg" },
99
100
  { "tag": "306", "required": "a", "key": "a" },
100
101
  // SKIP TAG 307 ON PURPOSE! N=0
101
102
  { "tag": "310", "required": "a", "key": "ab" },
@@ -140,7 +141,7 @@ const mergeConstraints = [
140
141
  { "tag": "385", "required": "a", "paired": "abmn", "key": "abmn" },
141
142
  { "tag": "386", "required": "a", "paired": "abmn", "key": "abmn" },
142
143
  { "tag": "388", "required": "a", "key": "a" },
143
- { "tag": "490", "required": "a", "key": "axvl" },
144
+ { "tag": "490", "required": "", "key": "axvl" },
144
145
  { "tag": "500", "required": "a", "key": "a" },
145
146
  { "tag": "501", "required": "a", "key": "a" },
146
147
  { "tag": "502", "required": "a", "key": "abcdgo" },
@@ -203,10 +204,10 @@ const mergeConstraints = [
203
204
  { "tag": "597", "required": "" },
204
205
  { "tag": "598", "required": "" },
205
206
  { "tag": "599", "required": "" },
206
- { "tag": "600", "required": "a", "paired": "tvxyz", "key": keyX00 },
207
- { "tag": "610", "required": "a", "paired": "btvxyz", "key": keyX10 },
208
- { "tag": "611", "required": "a", "paired": "tvxyz", "key": keyX11 },
209
- { "tag": "630", "required": "a", "paired": "atvxyz", "key": keyX30 },
207
+ { "tag": "600", "required": "a", "paired": `b${pairedTitleSubfields}vxyz`, "key": keyX00 },
208
+ { "tag": "610", "required": "a", "paired": `b${pairedTitleSubfields}vxyz`, "key": keyX10 },
209
+ { "tag": "611", "required": "a", "paired": `${pairedTitleSubfields}vxyz`, "key": keyX11 },
210
+ { "tag": "630", "required": "a", "paired": `${pairedTitleSubfields}vxyz`, "key": keyX30 },
210
211
  // NB! 700, 710 and 711 may have title parts that are handled elsewhere
211
212
  { "tag": "647", "required": "a", "paired": "avxyz", "key": "acdgvxyz02" },
212
213
  { "tag": "648", "required": "a", "paired": "avxyz", "key": "avxyz02" },
@@ -226,15 +227,15 @@ const mergeConstraints = [
226
227
  // N=0
227
228
  { "tag": "688", "required": "a" },
228
229
  // N=0
229
- { "tag": "700", "required": "a", "paired": "t", "key": keyX00 },
230
- // h/i/m/o/r/s/x are missing from 100
231
- { "tag": "710", "required": "a", "paired": "bt", "key": keyX10 },
230
+ { "tag": "700", "required": "a", "paired": `b${pairedTitleSubfields}x`, "key": keyX00 },
231
+ // h/i/m/o/r/s/x are missing from 100, NB! 's' is repeatable, but we are not merging them here!
232
+ { "tag": "710", "required": "a", "paired": `b${pairedTitleSubfields}x`, "key": keyX10 },
232
233
  // h/j/m/o/r/s/x are missing from 110
233
- { "tag": "711", "required": "a", "paired": "cdeflns", "key": keyX11 },
234
+ { "tag": "711", "required": "a", "paired": `cdef${pairedTitleSubfields}x`, "key": keyX11 },
234
235
  // h/i/s/x are missing from 711
235
236
  { "tag": "720", "required": "a", "key": "a" },
236
237
  // NB! 730 has no name part, key is used for title part
237
- { "tag": "730", "required": "a", "key": keyX30 },
238
+ { "tag": "730", "required": "a", "paired": `df${pairedTitleSubfields}x`, "key": keyX30 },
238
239
  // NB: 130->730 magic subfields might not agree...
239
240
  { "tag": "740", "required": "a", "key": "ahnp" },
240
241
  { "tag": "751", "required": "a", "key": "a" },
@@ -264,7 +265,7 @@ const mergeConstraints = [
264
265
  { "tag": "786", "required": "", "paired": "abcrstuxyz", "key": "abcdhijmprstuxyz4" },
265
266
  { "tag": "787", "required": "", "paired": "abcdhmstuxyz4" },
266
267
  { "tag": "788", "required": "", "paired": "stx", "key": "abdestx" },
267
- { "tag": "800", "required": "a", "paired": "t", "key": keyX00 },
268
+ { "tag": "800", "required": "a", "paired": "bt", "key": keyX00 },
268
269
  { "tag": "810", "required": "a", "paired": "bt", "key": keyX10 },
269
270
  { "tag": "811", "required": "a", "paired": "t", "key": keyX11 },
270
271
  { "tag": "830", "required": "a", "key": keyX30 },
@@ -315,21 +316,23 @@ const mergeConstraints = [
315
316
  { "tag": "LOW", "required": "" },
316
317
  { "tag": "SID", "required": "" }
317
318
  ];
318
- function constraintToValue(tagsConstraints, constraintName) {
319
- if (constraintName in tagsConstraints) {
320
- return tagsConstraints[constraintName];
321
- }
322
- return null;
323
- }
324
- export function getMergeConstraintsForTag(tag, constraintName) {
319
+ export function getMergeConstraintsForTag(tag, constraintName = void 0) {
325
320
  const tagsConstraintsArray = mergeConstraints.filter((entry) => tag === entry.tag);
326
321
  if (tagsConstraintsArray.length === 0) {
327
- debugDev(`WARNING No key found for ${tag}. Returning NULL!`);
328
- return null;
322
+ debugDev(`WARNING No key found for ${tag}!`);
323
+ }
324
+ if (!constraintName) {
325
+ return tagsConstraintsArray;
329
326
  }
330
327
  if (tagsConstraintsArray.length > 1) {
331
328
  debugDev(`WARNING Multiple values for '${constraintName}' (N=${tagsConstraintsArray.length}) found in ${tag}. Using first values.`);
332
329
  }
333
- return constraintToValue(tagsConstraintsArray[0], constraintName);
330
+ return tagsConstraintsArray.map((c) => constraintToValue(c, constraintName));
331
+ function constraintToValue(tagsConstraints, constraintName2) {
332
+ if (constraintName2 in tagsConstraints) {
333
+ return tagsConstraints[constraintName2];
334
+ }
335
+ return null;
336
+ }
334
337
  }
335
338
  //# sourceMappingURL=mergeConstraints.js.map