@natlibfi/marc-record-validators-melinda 11.6.7 → 12.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/{melinda-node-tests.yml → melinda-node-tests-and-publish.yml} +37 -12
- package/dist/access-rights.js +63 -91
- package/dist/access-rights.js.map +7 -1
- package/dist/access-rights.test.js +137 -0
- package/dist/access-rights.test.js.map +7 -0
- package/dist/addMissingField041.js +21 -53
- package/dist/addMissingField041.js.map +7 -1
- package/dist/addMissingField041.test.js +39 -0
- package/dist/addMissingField041.test.js.map +7 -0
- package/dist/addMissingField336.js +99 -191
- package/dist/addMissingField336.js.map +7 -1
- package/dist/addMissingField336.test.js +39 -0
- package/dist/addMissingField336.test.js.map +7 -0
- package/dist/addMissingField337.js +63 -132
- package/dist/addMissingField337.js.map +7 -1
- package/dist/addMissingField337.test.js +39 -0
- package/dist/addMissingField337.test.js.map +7 -0
- package/dist/addMissingField338.js +147 -253
- package/dist/addMissingField338.js.map +7 -1
- package/dist/addMissingField338.test.js +39 -0
- package/dist/addMissingField338.test.js.map +7 -0
- package/dist/cyrillux-usemarcon-replacement.js +119 -272
- package/dist/cyrillux-usemarcon-replacement.js.map +7 -1
- package/dist/cyrillux-usemarcon-replacement.test.js +43 -0
- package/dist/cyrillux-usemarcon-replacement.test.js.map +7 -0
- package/dist/cyrillux.js +119 -223
- package/dist/cyrillux.js.map +7 -1
- package/dist/cyrillux.test.js +39 -0
- package/dist/cyrillux.test.js.map +7 -0
- package/dist/disambiguateSeriesStatements.js +40 -81
- package/dist/disambiguateSeriesStatements.js.map +7 -1
- package/dist/disambiguateSeriesStatements.test.js +44 -0
- package/dist/disambiguateSeriesStatements.test.js.map +7 -0
- package/dist/double-commas.js +7 -14
- package/dist/double-commas.js.map +7 -1
- package/dist/double-commas.test.js +48 -0
- package/dist/double-commas.test.js.map +7 -0
- package/dist/duplicates-ind1.js +10 -31
- package/dist/duplicates-ind1.js.map +7 -1
- package/dist/duplicates-ind1.test.js +40 -0
- package/dist/duplicates-ind1.test.js.map +7 -0
- package/dist/empty-fields.js +10 -22
- package/dist/empty-fields.js.map +7 -1
- package/dist/empty-fields.test.js +129 -0
- package/dist/empty-fields.test.js.map +7 -0
- package/dist/ending-punctuation-conf.js +873 -769
- package/dist/ending-punctuation-conf.js.map +7 -1
- package/dist/ending-punctuation.js +156 -169
- package/dist/ending-punctuation.js.map +7 -1
- package/dist/ending-punctuation.test.js +2385 -0
- package/dist/ending-punctuation.test.js.map +7 -0
- package/dist/ending-whitespace.js +10 -35
- package/dist/ending-whitespace.js.map +7 -1
- package/dist/ending-whitespace.test.js +38 -0
- package/dist/ending-whitespace.test.js.map +7 -0
- package/dist/field-008-18-34-character-groups.js +40 -125
- package/dist/field-008-18-34-character-groups.js.map +7 -1
- package/dist/field-008-18-34-character-groups.test.js +45 -0
- package/dist/field-008-18-34-character-groups.test.js.map +7 -0
- package/dist/field-505-separators.js +19 -39
- package/dist/field-505-separators.js.map +7 -1
- package/dist/field-505-separators.test.js +45 -0
- package/dist/field-505-separators.test.js.map +7 -0
- package/dist/field-521-fix.js +19 -47
- package/dist/field-521-fix.js.map +7 -1
- package/dist/field-521-fix.test.js +44 -0
- package/dist/field-521-fix.test.js.map +7 -0
- package/dist/field-exclusion.js +37 -91
- package/dist/field-exclusion.js.map +7 -1
- package/dist/field-exclusion.test.js +821 -0
- package/dist/field-exclusion.test.js.map +7 -0
- package/dist/field-structure.js +52 -104
- package/dist/field-structure.js.map +7 -1
- package/dist/field-structure.test.js +587 -0
- package/dist/field-structure.test.js.map +7 -0
- package/dist/field33XUtils.js +119 -503
- package/dist/field33XUtils.js.map +7 -1
- package/dist/fields-present.js +11 -23
- package/dist/fields-present.js.map +7 -1
- package/dist/fields-present.test.js +95 -0
- package/dist/fields-present.test.js.map +7 -0
- package/dist/fix-33X.js +393 -431
- package/dist/fix-33X.js.map +7 -1
- package/dist/fix-33X.test.js +39 -0
- package/dist/fix-33X.test.js.map +7 -0
- package/dist/fix-country-codes.js +20 -50
- package/dist/fix-country-codes.js.map +7 -1
- package/dist/fix-country-codes.test.js +44 -0
- package/dist/fix-country-codes.test.js.map +7 -0
- package/dist/fix-language-codes.js +23 -53
- package/dist/fix-language-codes.js.map +7 -1
- package/dist/fix-language-codes.test.js +38 -0
- package/dist/fix-language-codes.test.js.map +7 -0
- package/dist/fixRelatorTerms.js +82 -209
- package/dist/fixRelatorTerms.js.map +7 -1
- package/dist/fixRelatorTerms.test.js +44 -0
- package/dist/fixRelatorTerms.test.js.map +7 -0
- package/dist/fixed-fields.js +21 -30
- package/dist/fixed-fields.js.map +7 -1
- package/dist/fixed-fields.test.js +87 -0
- package/dist/fixed-fields.test.js.map +7 -0
- package/dist/identical-fields.js +8 -24
- package/dist/identical-fields.js.map +7 -1
- package/dist/identical-fields.test.js +119 -0
- package/dist/identical-fields.test.js.map +7 -0
- package/dist/index.js +182 -413
- package/dist/index.js.map +7 -1
- package/dist/indicator-fixes.js +66 -94
- package/dist/indicator-fixes.js.map +7 -1
- package/dist/indicator-fixes.test.js +42 -0
- package/dist/indicator-fixes.test.js.map +7 -0
- package/dist/isbn-issn.js +71 -128
- package/dist/isbn-issn.js.map +7 -1
- package/dist/isbn-issn.test.js +398 -0
- package/dist/isbn-issn.test.js.map +7 -0
- package/dist/item-language.js +32 -65
- package/dist/item-language.js.map +7 -1
- package/dist/item-language.test.js +322 -0
- package/dist/item-language.test.js.map +7 -0
- package/dist/melindaCustomMergeFields.js +5182 -11233
- package/dist/melindaCustomMergeFields.js.map +7 -1
- package/dist/merge-fields/controlSubfields.js +75 -142
- package/dist/merge-fields/controlSubfields.js.map +7 -1
- package/dist/merge-fields/counterpartField.js +187 -379
- package/dist/merge-fields/counterpartField.js.map +7 -1
- package/dist/merge-fields/dataProvenance.js +29 -0
- package/dist/merge-fields/dataProvenance.js.map +7 -0
- package/dist/merge-fields/index.js +25 -50
- package/dist/merge-fields/index.js.map +7 -1
- package/dist/merge-fields/mergableIndicator.js +18 -51
- package/dist/merge-fields/mergableIndicator.js.map +7 -1
- package/dist/merge-fields/mergableTag.js +78 -30
- package/dist/merge-fields/mergableTag.js.map +7 -1
- package/dist/merge-fields/mergeConfig.js +66 -171
- package/dist/merge-fields/mergeConfig.js.map +7 -1
- package/dist/merge-fields/mergeConstraints.js +323 -1214
- package/dist/merge-fields/mergeConstraints.js.map +7 -1
- package/dist/merge-fields/mergeField.js +47 -111
- package/dist/merge-fields/mergeField.js.map +7 -1
- package/dist/merge-fields/mergeIndicator.js +64 -118
- package/dist/merge-fields/mergeIndicator.js.map +7 -1
- package/dist/merge-fields/mergeOrAddPostprocess.js +14 -38
- package/dist/merge-fields/mergeOrAddPostprocess.js.map +7 -1
- package/dist/merge-fields/mergeOrAddSubfield.js +62 -104
- package/dist/merge-fields/mergeOrAddSubfield.js.map +7 -1
- package/dist/merge-fields/mergeSubfield.js +47 -95
- package/dist/merge-fields/mergeSubfield.js.map +7 -1
- package/dist/merge-fields/removeDuplicateSubfields.js +18 -31
- package/dist/merge-fields/removeDuplicateSubfields.js.map +7 -1
- package/dist/merge-fields/worldKnowledge.js +15 -40
- package/dist/merge-fields/worldKnowledge.js.map +7 -1
- package/dist/merge-fields.test.js +46 -0
- package/dist/merge-fields.test.js.map +7 -0
- package/dist/mergeField500Lisapainokset.js +27 -56
- package/dist/mergeField500Lisapainokset.js.map +7 -1
- package/dist/mergeField500Lisapainokset.test.js +44 -0
- package/dist/mergeField500Lisapainokset.test.js.map +7 -0
- package/dist/mergeRelatorTermFields.js +33 -69
- package/dist/mergeRelatorTermFields.js.map +7 -1
- package/dist/mergeRelatorTermFields.test.js +44 -0
- package/dist/mergeRelatorTermFields.test.js.map +7 -0
- package/dist/modernize-502.js +23 -55
- package/dist/modernize-502.js.map +7 -1
- package/dist/modernize-502.test.js +38 -0
- package/dist/modernize-502.test.js.map +7 -0
- package/dist/multiple-subfield-0.js +23 -48
- package/dist/multiple-subfield-0.js.map +7 -1
- package/dist/multiple-subfield-0.test.js +44 -0
- package/dist/multiple-subfield-0.test.js.map +7 -0
- package/dist/non-breaking-space.js +11 -32
- package/dist/non-breaking-space.js.map +7 -1
- package/dist/non-breaking-space.test.js +38 -0
- package/dist/non-breaking-space.test.js.map +7 -0
- package/dist/normalize-dashes.js +18 -37
- package/dist/normalize-dashes.js.map +7 -1
- package/dist/normalize-dashes.test.js +44 -0
- package/dist/normalize-dashes.test.js.map +7 -0
- package/dist/normalize-identifiers.js +54 -140
- package/dist/normalize-identifiers.js.map +7 -1
- package/dist/normalize-identifiers.test.js +44 -0
- package/dist/normalize-identifiers.test.js.map +7 -0
- package/dist/normalize-qualifying-information.js +23 -48
- package/dist/normalize-qualifying-information.js.map +7 -1
- package/dist/normalize-qualifying-information.test.js +44 -0
- package/dist/normalize-qualifying-information.test.js.map +7 -0
- package/dist/normalize-utf8-diacritics.js +19 -105
- package/dist/normalize-utf8-diacritics.js.map +7 -1
- package/dist/normalize-utf8-diacritics.test.js +44 -0
- package/dist/normalize-utf8-diacritics.test.js.map +7 -0
- package/dist/normalizeFieldForComparison.js +91 -158
- package/dist/normalizeFieldForComparison.js.map +7 -1
- package/dist/normalizeSubfieldValueForComparison.js +37 -77
- package/dist/normalizeSubfieldValueForComparison.js.map +7 -1
- package/dist/prepublicationUtils.js +58 -111
- package/dist/prepublicationUtils.js.map +7 -1
- package/dist/punctuation/index.js +56 -72
- package/dist/punctuation/index.js.map +7 -1
- package/dist/punctuation/rules/aut.js +372 -331
- package/dist/punctuation/rules/aut.js.map +7 -1
- package/dist/punctuation/rules/bib.js +420 -373
- package/dist/punctuation/rules/bib.js.map +7 -1
- package/dist/punctuation/rules/index.js +7 -21
- package/dist/punctuation/rules/index.js.map +7 -1
- package/dist/punctuation.test.js +44 -0
- package/dist/punctuation.test.js.map +7 -0
- package/dist/punctuation2.js +259 -802
- package/dist/punctuation2.js.map +7 -1
- package/dist/punctuation2.test.js +44 -0
- package/dist/punctuation2.test.js.map +7 -0
- package/dist/reindexSubfield6OccurenceNumbers.js +61 -96
- package/dist/reindexSubfield6OccurenceNumbers.js.map +7 -1
- package/dist/reindexSubfield6OccurenceNumbers.test.js +44 -0
- package/dist/reindexSubfield6OccurenceNumbers.test.js.map +7 -0
- package/dist/removeDuplicateDataFields.js +102 -202
- package/dist/removeDuplicateDataFields.js.map +7 -1
- package/dist/removeDuplicateDataFields.test.js +44 -0
- package/dist/removeDuplicateDataFields.test.js.map +7 -0
- package/dist/removeInferiorDataFields.js +104 -227
- package/dist/removeInferiorDataFields.js.map +7 -1
- package/dist/removeInferiorDataFields.test.js +44 -0
- package/dist/removeInferiorDataFields.test.js.map +7 -0
- package/dist/resolvable-ext-references-melinda.js +25 -60
- package/dist/resolvable-ext-references-melinda.js.map +7 -1
- package/dist/resolvable-ext-references-melinda.test.js +160 -0
- package/dist/resolvable-ext-references-melinda.test.js.map +7 -0
- package/dist/resolveOrphanedSubfield6s.js +32 -63
- package/dist/resolveOrphanedSubfield6s.js.map +7 -1
- package/dist/resolveOrphanedSubfield6s.test.js +44 -0
- package/dist/resolveOrphanedSubfield6s.test.js.map +7 -0
- package/dist/sanitize-vocabulary-source-codes.js +27 -55
- package/dist/sanitize-vocabulary-source-codes.js.map +7 -1
- package/dist/sanitize-vocabulary-source-codes.test.js +45 -0
- package/dist/sanitize-vocabulary-source-codes.test.js.map +7 -0
- package/dist/sort-tags.js +13 -25
- package/dist/sort-tags.js.map +7 -1
- package/dist/sort-tags.test.js +261 -0
- package/dist/sort-tags.test.js.map +7 -0
- package/dist/sortFields.js +152 -222
- package/dist/sortFields.js.map +7 -1
- package/dist/sortFields.test.js +44 -0
- package/dist/sortFields.test.js.map +7 -0
- package/dist/sortRelatorTerms.js +30 -68
- package/dist/sortRelatorTerms.js.map +7 -1
- package/dist/sortRelatorTerms.test.js +44 -0
- package/dist/sortRelatorTerms.test.js.map +7 -0
- package/dist/sortSubfields.js +102 -255
- package/dist/sortSubfields.js.map +7 -1
- package/dist/sortSubfields.test.js +44 -0
- package/dist/sortSubfields.test.js.map +7 -0
- package/dist/stripPunctuation.js +13 -36
- package/dist/stripPunctuation.js.map +7 -1
- package/dist/stripPunctuation.test.js +44 -0
- package/dist/stripPunctuation.test.js.map +7 -0
- package/dist/subfield-exclusion.js +28 -75
- package/dist/subfield-exclusion.js.map +7 -1
- package/dist/subfield-exclusion.test.js +471 -0
- package/dist/subfield-exclusion.test.js.map +7 -0
- package/dist/subfield6Utils.js +107 -269
- package/dist/subfield6Utils.js.map +7 -1
- package/dist/subfield8Utils.js +26 -50
- package/dist/subfield8Utils.js.map +7 -1
- package/dist/subfieldValueNormalizations.js +40 -74
- package/dist/subfieldValueNormalizations.js.map +7 -1
- package/dist/subfieldValueNormalizations.test.js +45 -0
- package/dist/subfieldValueNormalizations.test.js.map +7 -0
- package/dist/sync-007-and-300.js +22 -53
- package/dist/sync-007-and-300.js.map +7 -1
- package/dist/sync-007-and-300.test.js +44 -0
- package/dist/sync-007-and-300.test.js.map +7 -0
- package/dist/translate-terms.js +67 -155
- package/dist/translate-terms.js.map +7 -1
- package/dist/translate-terms.test.js +54 -0
- package/dist/translate-terms.test.js.map +7 -0
- package/dist/typeOfDate-008.js +10 -25
- package/dist/typeOfDate-008.js.map +7 -1
- package/dist/typeOfDate-008.test.js +40 -0
- package/dist/typeOfDate-008.test.js.map +7 -0
- package/dist/unicode-decomposition.js +94 -107
- package/dist/unicode-decomposition.js.map +7 -1
- package/dist/unicode-decomposition.test.js +94 -0
- package/dist/unicode-decomposition.test.js.map +7 -0
- package/dist/update-field-540.js +30 -75
- package/dist/update-field-540.js.map +7 -1
- package/dist/update-field-540.test.js +44 -0
- package/dist/update-field-540.test.js.map +7 -0
- package/dist/urn.js +55 -128
- package/dist/urn.js.map +7 -1
- package/dist/urn.test.js +44 -0
- package/dist/urn.test.js.map +7 -0
- package/dist/utils.js +78 -126
- package/dist/utils.js.map +7 -1
- package/eslint.config.mjs +1 -2
- package/package.json +28 -101
- package/src/access-rights.js +1 -1
- package/src/{access-rights.spec.js → access-rights.test.js} +9 -10
- package/src/addMissingField041.js +1 -1
- package/src/{addMissingField336.spec.js → addMissingField041.test.js} +13 -14
- package/src/addMissingField336.js +3 -3
- package/src/{addMissingField041.spec.js → addMissingField336.test.js} +13 -14
- package/src/addMissingField337.js +2 -2
- package/src/{addMissingField337.spec.js → addMissingField337.test.js} +13 -14
- package/src/addMissingField338.js +2 -2
- package/src/{addMissingField338.spec.js → addMissingField338.test.js} +13 -14
- package/src/cyrillux-usemarcon-replacement.js +18 -18
- package/src/{cyrillux-usemarcon-replacement.spec.js → cyrillux-usemarcon-replacement.test.js} +17 -14
- package/src/cyrillux.js +19 -12
- package/src/{cyrillux.spec.js → cyrillux.test.js} +13 -14
- package/src/disambiguateSeriesStatements.js +2 -2
- package/src/{disambiguateSeriesStatements.spec.js → disambiguateSeriesStatements.test.js} +12 -13
- package/src/double-commas.js +1 -1
- package/src/{double-commas.spec.js → double-commas.test.js} +9 -11
- package/src/duplicates-ind1.js +1 -1
- package/src/{duplicates-ind1.spec.js → duplicates-ind1.test.js} +12 -13
- package/src/{empty-fields.spec.js → empty-fields.test.js} +11 -13
- package/src/ending-punctuation-conf.js +6 -5
- package/src/ending-punctuation.js +115 -24
- package/src/{ending-punctuation.spec.js → ending-punctuation.test.js} +357 -275
- package/src/{ending-whitespace.spec.js → ending-whitespace.test.js} +12 -13
- package/src/field-008-18-34-character-groups.js +2 -2
- package/src/{field-008-18-34-character-groups.spec.js → field-008-18-34-character-groups.test.js} +13 -13
- package/src/field-505-separators.js +3 -3
- package/src/{field-505-separators.spec.js → field-505-separators.test.js} +16 -14
- package/src/field-521-fix.js +2 -2
- package/src/{field-521-fix.spec.js → field-521-fix.test.js} +12 -13
- package/src/field-exclusion.js +1 -1
- package/src/{field-exclusion.spec.js → field-exclusion.test.js} +60 -57
- package/src/{field-structure.spec.js → field-structure.test.js} +29 -29
- package/src/{fields-present.spec.js → fields-present.test.js} +12 -15
- package/src/fix-33X.js +4 -4
- package/src/{fix-33X.spec.js → fix-33X.test.js} +13 -14
- package/src/fix-country-codes.js +1 -1
- package/src/{fix-country-codes.spec.js → fix-country-codes.test.js} +12 -13
- package/src/fix-language-codes.js +5 -5
- package/src/{fix-language-codes.spec.js → fix-language-codes.test.js} +12 -13
- package/src/fixRelatorTerms.js +5 -5
- package/src/{fixRelatorTerms.spec.js → fixRelatorTerms.test.js} +13 -13
- package/src/{fixed-fields.spec.js → fixed-fields.test.js} +11 -14
- package/src/identical-fields.js +1 -1
- package/src/{identical-fields.spec.js → identical-fields.test.js} +9 -11
- package/src/index.js +132 -59
- package/src/indicator-fixes.js +17 -4
- package/src/{indicator-fixes.spec.js → indicator-fixes.test.js} +9 -12
- package/src/isbn-issn.js +12 -7
- package/src/{isbn-issn.spec.js → isbn-issn.test.js} +20 -22
- package/src/{item-language.spec.js → item-language.test.js} +21 -22
- package/src/melindaCustomMergeFields.js +1 -1
- package/src/merge-fields/controlSubfields.js +1 -1
- package/src/merge-fields/counterpartField.js +14 -9
- package/src/merge-fields/dataProvenance.js +41 -0
- package/src/merge-fields/index.js +12 -3
- package/src/merge-fields/mergableIndicator.js +1 -1
- package/src/merge-fields/mergeField.js +8 -8
- package/src/merge-fields/mergeIndicator.js +1 -1
- package/src/merge-fields/mergeOrAddPostprocess.js +4 -4
- package/src/merge-fields/mergeOrAddSubfield.js +2 -2
- package/src/merge-fields/mergeSubfield.js +4 -4
- package/src/merge-fields/removeDuplicateSubfields.js +2 -2
- package/src/{merge-fields.spec.js → merge-fields.test.js} +18 -15
- package/src/mergeField500Lisapainokset.js +1 -1
- package/src/{mergeField500Lisapainokset.spec.js → mergeField500Lisapainokset.test.js} +12 -13
- package/src/mergeRelatorTermFields.js +5 -7
- package/src/{mergeRelatorTermFields.spec.js → mergeRelatorTermFields.test.js} +12 -13
- package/src/modernize-502.js +1 -1
- package/src/{modernize-502.spec.js → modernize-502.test.js} +12 -13
- package/src/multiple-subfield-0.js +3 -3
- package/src/{multiple-subfield-0.spec.js → multiple-subfield-0.test.js} +13 -13
- package/src/{non-breaking-space.spec.js → non-breaking-space.test.js} +12 -13
- package/src/normalize-dashes.js +2 -2
- package/src/{normalize-dashes.spec.js → normalize-dashes.test.js} +12 -13
- package/src/normalize-identifiers.js +1 -1
- package/src/{normalize-identifiers.spec.js → normalize-identifiers.test.js} +12 -13
- package/src/normalize-qualifying-information.js +2 -2
- package/src/{normalize-qualifying-information.spec.js → normalize-qualifying-information.test.js} +12 -13
- package/src/normalize-utf8-diacritics.js +2 -2
- package/src/{normalize-utf8-diacritics.spec.js → normalize-utf8-diacritics.test.js} +13 -13
- package/src/normalizeFieldForComparison.js +32 -6
- package/src/normalizeSubfieldValueForComparison.js +1 -1
- package/src/prepublicationUtils.js +4 -4
- package/src/punctuation/index.js +1 -1
- package/src/punctuation/rules/index.js +2 -2
- package/src/{punctuation.spec.js → punctuation.test.js} +12 -13
- package/src/punctuation2.js +17 -8
- package/src/{punctuation2.spec.js → punctuation2.test.js} +12 -13
- package/src/reindexSubfield6OccurenceNumbers.js +5 -7
- package/src/{reindexSubfield6OccurenceNumbers.spec.js → reindexSubfield6OccurenceNumbers.test.js} +12 -13
- package/src/removeDuplicateDataFields.js +11 -19
- package/src/{removeDuplicateDataFields.spec.js → removeDuplicateDataFields.test.js} +12 -13
- package/src/removeInferiorDataFields.js +15 -12
- package/src/{removeInferiorDataFields.spec.js → removeInferiorDataFields.test.js} +13 -13
- package/src/resolvable-ext-references-melinda.js +1 -1
- package/src/{resolvable-ext-references-melinda.spec.js → resolvable-ext-references-melinda.test.js} +42 -27
- package/src/resolveOrphanedSubfield6s.js +6 -6
- package/src/{resolveOrphanedSubfield6s.spec.js → resolveOrphanedSubfield6s.test.js} +13 -13
- package/src/sanitize-vocabulary-source-codes.js +4 -4
- package/src/{sanitize-vocabulary-source-codes.spec.js → sanitize-vocabulary-source-codes.test.js} +16 -14
- package/src/{sort-tags.spec.js → sort-tags.test.js} +9 -11
- package/src/sortFields.js +4 -4
- package/src/{sortFields.spec.js → sortFields.test.js} +12 -13
- package/src/sortRelatorTerms.js +3 -3
- package/src/{sortRelatorTerms.spec.js → sortRelatorTerms.test.js} +13 -13
- package/src/sortSubfields.js +8 -6
- package/src/{sortSubfields.spec.js → sortSubfields.test.js} +13 -13
- package/src/stripPunctuation.js +3 -3
- package/src/{stripPunctuation.spec.js → stripPunctuation.test.js} +13 -13
- package/src/subfield-exclusion.js +1 -1
- package/src/{subfield-exclusion.spec.js → subfield-exclusion.test.js} +45 -36
- package/src/subfield6Utils.js +6 -10
- package/src/subfield8Utils.js +4 -4
- package/src/subfieldValueNormalizations.js +3 -3
- package/src/{subfieldValueNormalizations.spec.js → subfieldValueNormalizations.test.js} +18 -14
- package/src/sync-007-and-300.js +2 -2
- package/src/{sync-007-and-300.spec.js → sync-007-and-300.test.js} +13 -13
- package/src/translate-terms.js +3 -3
- package/src/translate-terms.test.js +75 -0
- package/src/{typeOfDate-008.spec.js → typeOfDate-008.test.js} +12 -13
- package/src/{unicode-decomposition.spec.js → unicode-decomposition.test.js} +10 -16
- package/src/update-field-540.js +2 -2
- package/src/{update-field-540.spec.js → update-field-540.test.js} +13 -10
- package/src/urn.js +2 -2
- package/src/{urn.spec.js → urn.test.js} +12 -13
- package/src/utils.js +21 -5
- package/test-fixtures/field-505-separators/03/expectedResult.json +3 -1
- package/test-fixtures/field-505-separators/03/record.json +3 -0
- package/test-fixtures/indicator-fixes/10/expectedResult.json +11 -0
- package/test-fixtures/indicator-fixes/10/metadata.json +4 -0
- package/test-fixtures/indicator-fixes/10/record.json +11 -0
- package/test-fixtures/merge-fields/f05/expectedResult.json +24 -0
- package/test-fixtures/merge-fields/f05/metadata.json +6 -0
- package/test-fixtures/merge-fields/f05/record.json +30 -0
- package/test-fixtures/normalize-subfield-value/01/metadata.json +4 -1
- package/test-fixtures/normalize-subfield-value/01/record.json +3 -0
- package/test-fixtures/normalize-subfield-value/02/expectedResult.json +3 -1
- package/test-fixtures/normalize-subfield-value/02/metadata.json +2 -1
- package/test-fixtures/normalize-subfield-value/02/record.json +3 -0
- package/test-fixtures/remove-inferior-datafields/f16/expectedResult.json +12 -0
- package/test-fixtures/remove-inferior-datafields/f16/metadata.json +5 -0
- package/test-fixtures/remove-inferior-datafields/f16/record.json +14 -0
- package/test-fixtures/sanitize-vocabulary-source-codes/f03/expectedResult.json +3 -1
- package/test-fixtures/sanitize-vocabulary-source-codes/f04/expectedResult.json +3 -1
- package/test-fixtures/sanitize-vocabulary-source-codes/v04/metadata.json +1 -4
- package/test-fixtures/sanitize-vocabulary-source-codes/v04/record.json +1 -1
- package/test-fixtures/translate-terms-data.js +42 -0
- package/dist/access-rights.spec.js +0 -195
- package/dist/access-rights.spec.js.map +0 -1
- package/dist/addMissingField041.spec.js +0 -45
- package/dist/addMissingField041.spec.js.map +0 -1
- package/dist/addMissingField336.spec.js +0 -45
- package/dist/addMissingField336.spec.js.map +0 -1
- package/dist/addMissingField337.spec.js +0 -43
- package/dist/addMissingField337.spec.js.map +0 -1
- package/dist/addMissingField338.spec.js +0 -45
- package/dist/addMissingField338.spec.js.map +0 -1
- package/dist/cyrillux-usemarcon-replacement.spec.js +0 -45
- package/dist/cyrillux-usemarcon-replacement.spec.js.map +0 -1
- package/dist/cyrillux.spec.js +0 -46
- package/dist/cyrillux.spec.js.map +0 -1
- package/dist/disambiguateSeriesStatements.spec.js +0 -51
- package/dist/disambiguateSeriesStatements.spec.js.map +0 -1
- package/dist/double-commas.spec.js +0 -73
- package/dist/double-commas.spec.js.map +0 -1
- package/dist/duplicates-ind1.spec.js +0 -45
- package/dist/duplicates-ind1.spec.js.map +0 -1
- package/dist/empty-fields.spec.js +0 -118
- package/dist/empty-fields.spec.js.map +0 -1
- package/dist/ending-punctuation.spec.js +0 -2654
- package/dist/ending-punctuation.spec.js.map +0 -1
- package/dist/ending-whitespace.spec.js +0 -42
- package/dist/ending-whitespace.spec.js.map +0 -1
- package/dist/field-008-18-34-character-groups.spec.js +0 -51
- package/dist/field-008-18-34-character-groups.spec.js.map +0 -1
- package/dist/field-505-separators.spec.js +0 -51
- package/dist/field-505-separators.spec.js.map +0 -1
- package/dist/field-521-fix.spec.js +0 -51
- package/dist/field-521-fix.spec.js.map +0 -1
- package/dist/field-exclusion.spec.js +0 -1054
- package/dist/field-exclusion.spec.js.map +0 -1
- package/dist/field-structure.spec.js +0 -535
- package/dist/field-structure.spec.js.map +0 -1
- package/dist/fields-present.spec.js +0 -121
- package/dist/fields-present.spec.js.map +0 -1
- package/dist/fix-33X.spec.js +0 -45
- package/dist/fix-33X.spec.js.map +0 -1
- package/dist/fix-country-codes.spec.js +0 -51
- package/dist/fix-country-codes.spec.js.map +0 -1
- package/dist/fix-language-codes.spec.js +0 -44
- package/dist/fix-language-codes.spec.js.map +0 -1
- package/dist/fixRelatorTerms.spec.js +0 -51
- package/dist/fixRelatorTerms.spec.js.map +0 -1
- package/dist/fixed-fields.spec.js +0 -140
- package/dist/fixed-fields.spec.js.map +0 -1
- package/dist/identical-fields.spec.js +0 -99
- package/dist/identical-fields.spec.js.map +0 -1
- package/dist/indicator-fixes.spec.js +0 -51
- package/dist/indicator-fixes.spec.js.map +0 -1
- package/dist/isbn-issn.spec.js +0 -595
- package/dist/isbn-issn.spec.js.map +0 -1
- package/dist/item-language.spec.js +0 -306
- package/dist/item-language.spec.js.map +0 -1
- package/dist/melindaCustomMergeFields.json +0 -5120
- package/dist/merge-fields.spec.js +0 -51
- package/dist/merge-fields.spec.js.map +0 -1
- package/dist/mergeField500Lisapainokset.spec.js +0 -51
- package/dist/mergeField500Lisapainokset.spec.js.map +0 -1
- package/dist/mergeRelatorTermFields.spec.js +0 -51
- package/dist/mergeRelatorTermFields.spec.js.map +0 -1
- package/dist/modernize-502.spec.js +0 -49
- package/dist/modernize-502.spec.js.map +0 -1
- package/dist/multiple-subfield-0.spec.js +0 -51
- package/dist/multiple-subfield-0.spec.js.map +0 -1
- package/dist/non-breaking-space.spec.js +0 -42
- package/dist/non-breaking-space.spec.js.map +0 -1
- package/dist/normalize-dashes.spec.js +0 -51
- package/dist/normalize-dashes.spec.js.map +0 -1
- package/dist/normalize-identifiers.spec.js +0 -51
- package/dist/normalize-identifiers.spec.js.map +0 -1
- package/dist/normalize-qualifying-information.spec.js +0 -51
- package/dist/normalize-qualifying-information.spec.js.map +0 -1
- package/dist/normalize-utf8-diacritics.spec.js +0 -51
- package/dist/normalize-utf8-diacritics.spec.js.map +0 -1
- package/dist/punctuation.spec.js +0 -51
- package/dist/punctuation.spec.js.map +0 -1
- package/dist/punctuation2.spec.js +0 -51
- package/dist/punctuation2.spec.js.map +0 -1
- package/dist/reindexSubfield6OccurenceNumbers.spec.js +0 -51
- package/dist/reindexSubfield6OccurenceNumbers.spec.js.map +0 -1
- package/dist/removeDuplicateDataFields.spec.js +0 -51
- package/dist/removeDuplicateDataFields.spec.js.map +0 -1
- package/dist/removeInferiorDataFields.spec.js +0 -51
- package/dist/removeInferiorDataFields.spec.js.map +0 -1
- package/dist/resolvable-ext-references-melinda.spec.js +0 -166
- package/dist/resolvable-ext-references-melinda.spec.js.map +0 -1
- package/dist/resolveOrphanedSubfield6s.spec.js +0 -51
- package/dist/resolveOrphanedSubfield6s.spec.js.map +0 -1
- package/dist/sanitize-vocabulary-source-codes.spec.js +0 -51
- package/dist/sanitize-vocabulary-source-codes.spec.js.map +0 -1
- package/dist/sort-tags.spec.js +0 -207
- package/dist/sort-tags.spec.js.map +0 -1
- package/dist/sortFields.spec.js +0 -51
- package/dist/sortFields.spec.js.map +0 -1
- package/dist/sortRelatorTerms.spec.js +0 -51
- package/dist/sortRelatorTerms.spec.js.map +0 -1
- package/dist/sortSubfields.spec.js +0 -52
- package/dist/sortSubfields.spec.js.map +0 -1
- package/dist/stripPunctuation.spec.js +0 -51
- package/dist/stripPunctuation.spec.js.map +0 -1
- package/dist/subfield-exclusion.spec.js +0 -523
- package/dist/subfield-exclusion.spec.js.map +0 -1
- package/dist/subfieldValueNormalizations.spec.js +0 -51
- package/dist/subfieldValueNormalizations.spec.js.map +0 -1
- package/dist/sync-007-and-300.spec.js +0 -51
- package/dist/sync-007-and-300.spec.js.map +0 -1
- package/dist/translate-terms.spec.js +0 -51
- package/dist/translate-terms.spec.js.map +0 -1
- package/dist/typeOfDate-008.spec.js +0 -47
- package/dist/typeOfDate-008.spec.js.map +0 -1
- package/dist/unicode-decomposition.spec.js +0 -91
- package/dist/unicode-decomposition.spec.js.map +0 -1
- package/dist/update-field-540.spec.js +0 -51
- package/dist/update-field-540.spec.js.map +0 -1
- package/dist/urn.spec.js +0 -52
- package/dist/urn.spec.js.map +0 -1
- package/src/melindaCustomMergeFields.json +0 -5120
- package/src/translate-terms.spec.js +0 -52
|
@@ -1,127 +1,91 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
var _normalizeIdentifiers = require("../normalize-identifiers");
|
|
15
|
-
var _mergeConstraints = require("./mergeConstraints");
|
|
16
|
-
var _controlSubfields = require("./controlSubfields");
|
|
17
|
-
var _mergableIndicator = require("./mergableIndicator");
|
|
18
|
-
var _normalizeSubfieldValueForComparison = require("../normalizeSubfieldValueForComparison");
|
|
19
|
-
var _worldKnowledge = require("./worldKnowledge");
|
|
20
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
|
-
// For each incoming field that
|
|
22
|
-
|
|
23
|
-
// This should be done via our own normalizer:
|
|
24
|
-
|
|
25
|
-
const debug = (0, _debug.default)('@natlibfi/marc-record-validators-melinda:mergeField:counterpart');
|
|
26
|
-
//const debugData = debug.extend('data');
|
|
27
|
-
const debugDev = debug.extend('dev');
|
|
28
|
-
const irrelevantSubfieldsInNameAndTitlePartComparison = '5689';
|
|
1
|
+
import createDebugLogger from "debug";
|
|
2
|
+
import { fieldHasSubfield, fieldHasNSubfields, fieldHasMultipleSubfields, fieldToString, nvdebug, removeCopyright } from "../utils.js";
|
|
3
|
+
import { cloneAndNormalizeFieldForComparison, cloneAndRemovePunctuation } from "../normalizeFieldForComparison.js";
|
|
4
|
+
import { normalizeControlSubfieldValue } from "../normalize-identifiers.js";
|
|
5
|
+
import { getMergeConstraintsForTag } from "./mergeConstraints.js";
|
|
6
|
+
import { controlSubfieldsPermitMerge } from "./controlSubfields.js";
|
|
7
|
+
import { mergableIndicator1, mergableIndicator2 } from "./mergableIndicator.js";
|
|
8
|
+
import { partsAgree } from "../normalizeSubfieldValueForComparison.js";
|
|
9
|
+
import { normalizeForSamenessCheck, valueCarriesMeaning } from "./worldKnowledge.js";
|
|
10
|
+
import { provenanceSubfieldsPermitMerge } from "./dataProvenance.js";
|
|
11
|
+
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:mergeField:counterpart");
|
|
12
|
+
const debugDev = debug.extend("dev");
|
|
13
|
+
const irrelevantSubfieldsInNameAndTitlePartComparison = "5689";
|
|
29
14
|
const counterpartRegexps = {
|
|
30
15
|
// NB! tag is from source!
|
|
31
16
|
// Note that in the normal case, all source 1XX fields have been converted to 7XX fields.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
"100": /^[17]00$/u,
|
|
18
|
+
"110": /^[17]10$/u,
|
|
19
|
+
"111": /^[17]11$/u,
|
|
20
|
+
"130": /^[17]30$/u,
|
|
21
|
+
"260": /^26[04]$/u,
|
|
22
|
+
"264": /^26[04]$/u,
|
|
23
|
+
"700": /^[17]00$/u,
|
|
24
|
+
"710": /^[17]10$/u,
|
|
25
|
+
"711": /^[17]11$/u,
|
|
26
|
+
"730": /^[17]30$/u,
|
|
42
27
|
// Hacks:
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
"940": /^[29]40$/u,
|
|
29
|
+
"973": /^[79]73$/u
|
|
45
30
|
};
|
|
46
31
|
const counterpartRegexpsSingle = {
|
|
47
32
|
// when base===source, never merge 1XX to 7XX, always 7XX to 1XX! Also, don't merge 264 to 260.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
33
|
+
"260": /^26[04]$/u,
|
|
34
|
+
"700": /^[17]00$/u,
|
|
35
|
+
"110": /^[17]10$/u,
|
|
36
|
+
"111": /^[17]11$/u,
|
|
37
|
+
"130": /^[17]30$/u,
|
|
53
38
|
// Hacks:
|
|
54
|
-
|
|
55
|
-
|
|
39
|
+
"940": /^[29]40$/u,
|
|
40
|
+
"973": /^[79]73$/u
|
|
56
41
|
};
|
|
57
|
-
|
|
58
|
-
/*
|
|
59
|
-
function differentPublisherSubfields(field1, field2) {
|
|
60
|
-
if (field1.tag === '260' && field2.tag === '264' && field2.ind2 === '3') {
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
if (field1.tag === '264' && field1.ind2 === '3' && field2.tag === '260') {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
function splitToNameAndQualifier(value) {
|
|
42
|
+
export function splitToNameAndQualifier(value) {
|
|
71
43
|
if (value.match(/^.* \([^()]+\)$/u)) {
|
|
72
|
-
const name = value.replace(/^(.*) \([^()]+\)$/u,
|
|
73
|
-
const qualifier = value.replace(/^.* (\([^()]+\))$/u,
|
|
44
|
+
const name = value.replace(/^(.*) \([^()]+\)$/u, "$1");
|
|
45
|
+
const qualifier = value.replace(/^.* (\([^()]+\))$/u, "$1");
|
|
74
46
|
return [name, qualifier];
|
|
75
47
|
}
|
|
76
|
-
return [value,
|
|
48
|
+
return [value, void 0];
|
|
77
49
|
}
|
|
78
|
-
function splitToNameAndQualifierAndProcessName(name) {
|
|
79
|
-
//const nameOnly = name.replace(/(?: \([^)]+\)| abp?| Kustannus| Kustannus Oy|, kustannusosakeyhtiö| oyj?| ry)$/ugi, '');
|
|
50
|
+
export function splitToNameAndQualifierAndProcessName(name) {
|
|
80
51
|
const [qualifierlessName, qualifier] = splitToNameAndQualifier(name);
|
|
81
52
|
const [prefix, basename, suffix] = stripPrefixAndSuffix(qualifierlessName);
|
|
82
|
-
return {
|
|
83
|
-
name: getBestName(basename).toLowerCase(),
|
|
84
|
-
prefix,
|
|
85
|
-
suffix,
|
|
86
|
-
qualifier
|
|
87
|
-
};
|
|
53
|
+
return { name: getBestName(basename).toLowerCase(), prefix, suffix, qualifier };
|
|
88
54
|
function stripPrefixAndSuffix(companyName) {
|
|
89
|
-
const [nameOnly,
|
|
90
|
-
const [nameOnly2,
|
|
91
|
-
return [
|
|
92
|
-
}
|
|
93
|
-
function extractSuffix(
|
|
94
|
-
const nameOnly =
|
|
95
|
-
if (nameOnly ===
|
|
96
|
-
return [
|
|
55
|
+
const [nameOnly, suffix2] = extractSuffix(companyName);
|
|
56
|
+
const [nameOnly2, prefix2] = extractPrefix(nameOnly);
|
|
57
|
+
return [prefix2, nameOnly2, suffix2];
|
|
58
|
+
}
|
|
59
|
+
function extractSuffix(name2) {
|
|
60
|
+
const nameOnly = name2.replace(/(?: \([^)]+\)| abp?| Kustannus| Kustannus Oy|, kustannusosakeyhtiö| oyj?| ry)$/ugi, "");
|
|
61
|
+
if (nameOnly === name2) {
|
|
62
|
+
return [name2, void 0];
|
|
97
63
|
}
|
|
98
|
-
return [nameOnly,
|
|
64
|
+
return [nameOnly, name2.substring(nameOnly.length).replace(/^,? /u, "")];
|
|
99
65
|
}
|
|
100
|
-
function extractPrefix(
|
|
101
|
-
const nameOnly =
|
|
102
|
-
if (nameOnly ===
|
|
103
|
-
return [
|
|
66
|
+
function extractPrefix(name2) {
|
|
67
|
+
const nameOnly = name2.replace(/^(?:Ab|Kustannusosakeyhtiö|Kustannus Oy|Oy) /ugi, "");
|
|
68
|
+
if (nameOnly === name2) {
|
|
69
|
+
return [name2, void 0];
|
|
104
70
|
}
|
|
105
|
-
return [nameOnly,
|
|
71
|
+
return [nameOnly, name2.substring(0, name2.length - nameOnly.length - 1)];
|
|
106
72
|
}
|
|
107
|
-
function getBestName(
|
|
108
|
-
const NAME =
|
|
109
|
-
if (NAME ===
|
|
110
|
-
return
|
|
73
|
+
function getBestName(name2) {
|
|
74
|
+
const NAME = name2.toUpperCase();
|
|
75
|
+
if (NAME === "WSOY") {
|
|
76
|
+
return "Werner S\xF6derstr\xF6m osakeyhti\xF6";
|
|
111
77
|
}
|
|
112
|
-
if (NAME ===
|
|
113
|
-
return
|
|
78
|
+
if (NAME === "NTAMO") {
|
|
79
|
+
return "ntamo";
|
|
114
80
|
}
|
|
115
|
-
return
|
|
81
|
+
return name2;
|
|
116
82
|
}
|
|
117
83
|
}
|
|
118
|
-
function canContainOptionalQualifier(tag, subfieldCode) {
|
|
119
|
-
|
|
120
|
-
if (tag === '300' && subfieldCode === 'a') {
|
|
84
|
+
export function canContainOptionalQualifier(tag, subfieldCode) {
|
|
85
|
+
if (tag === "300" && subfieldCode === "a") {
|
|
121
86
|
return true;
|
|
122
87
|
}
|
|
123
|
-
|
|
124
|
-
if (tag === '776' && subfieldCode === 'i') {
|
|
88
|
+
if (tag === "776" && subfieldCode === "i") {
|
|
125
89
|
return true;
|
|
126
90
|
}
|
|
127
91
|
return false;
|
|
@@ -132,174 +96,101 @@ function withAndWithoutQualifierAgree(value1, value2, tag, subfieldCode) {
|
|
|
132
96
|
}
|
|
133
97
|
const [name1, qualifier1] = splitToNameAndQualifier(value1);
|
|
134
98
|
const [name2, qualifier2] = splitToNameAndQualifier(value2);
|
|
135
|
-
|
|
136
|
-
//nvdebug(`CN1: '${name1}', '${qualifier1}'`, debugDev);
|
|
137
|
-
//nvdebug(`CN2: '${name2}', '${qualifier2}'`, debugDev);
|
|
138
|
-
|
|
139
99
|
if (name1.toLowerCase() !== name2.toLowerCase()) {
|
|
140
100
|
return false;
|
|
141
101
|
}
|
|
142
|
-
|
|
143
|
-
// If either value does not have a qualifier, they are considered equals:
|
|
144
|
-
if (qualifier1 === undefined || qualifier2 === undefined || qualifier1.toLowerCase() === qualifier2.toLowerCase()) {
|
|
102
|
+
if (qualifier1 === void 0 || qualifier2 === void 0 || qualifier1.toLowerCase() === qualifier2.toLowerCase()) {
|
|
145
103
|
return true;
|
|
146
104
|
}
|
|
147
105
|
return false;
|
|
148
106
|
}
|
|
149
107
|
function corporateNamesAgree(value1, value2, tag, subfieldCode) {
|
|
150
|
-
if (subfieldCode !==
|
|
108
|
+
if (subfieldCode !== "a" || !["110", "610", "710", "810"].includes(tag)) {
|
|
151
109
|
return false;
|
|
152
110
|
}
|
|
153
111
|
const nameData1 = splitToNameAndQualifierAndProcessName(value1);
|
|
154
112
|
const nameData2 = splitToNameAndQualifierAndProcessName(value2);
|
|
155
|
-
|
|
156
|
-
|
|
113
|
+
nvdebug(`CN1: '${nameData1.name}', '${nameData1.qualifier}'`, debugDev);
|
|
114
|
+
nvdebug(`CN2: '${nameData2.name}', '${nameData2.qualifier}'`, debugDev);
|
|
157
115
|
if (nameData1.name !== nameData2.name) {
|
|
158
116
|
return false;
|
|
159
117
|
}
|
|
160
118
|
if (nameData1.qualifier && nameData2.qualifier && nameData1.qualifier !== nameData2.qualifier) {
|
|
161
119
|
return false;
|
|
162
120
|
}
|
|
163
|
-
// Currently all prefixes and suffixes are publisher information, so there's no point comparing them any further...
|
|
164
|
-
|
|
165
121
|
return true;
|
|
166
|
-
|
|
167
|
-
/*
|
|
168
|
-
function isKustantaja(nameData) {
|
|
169
|
-
if (nameData.suffix.match(/^(?:Kustannus|Kustannus oy|kustannusosakeyhtiö)$/iu)) {
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
if (nameData.prefix.match(/^Kustannus Oy$/i)) {
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
*/
|
|
178
122
|
}
|
|
179
123
|
function pairableValue(tag, subfieldCode, value1, value2) {
|
|
180
|
-
// This function could just return true or false.
|
|
181
|
-
// I thought of preference when I wrote this, but preference implemented *here* (modularity). mergeFields.js should handle preference.
|
|
182
124
|
if (withAndWithoutQualifierAgree(value1, value2, tag, subfieldCode)) {
|
|
183
|
-
// 300$a "whatever" and "whatever (123 sivua)"
|
|
184
125
|
return value1;
|
|
185
126
|
}
|
|
186
|
-
if (
|
|
187
|
-
// Pure baseness: here we assume that base's value1 is better than source's value2.
|
|
127
|
+
if (partsAgree(value1, value2, tag, subfieldCode) || corporateNamesAgree(value1, value2, tag, subfieldCode)) {
|
|
188
128
|
return value1;
|
|
189
129
|
}
|
|
190
|
-
return
|
|
130
|
+
return void 0;
|
|
191
131
|
}
|
|
192
132
|
function counterpartExtraNormalize(tag, subfieldCode, value) {
|
|
193
|
-
|
|
194
|
-
value = value.replace(
|
|
195
|
-
|
|
196
|
-
value = value
|
|
197
|
-
value = value.replace(
|
|
198
|
-
|
|
199
|
-
value = (0, _utils.removeCopyright)(value);
|
|
200
|
-
value = value.replace(/http:\/\//ug, 'https://'); // MET-501: http vs https
|
|
201
|
-
value = (0, _worldKnowledge.normalizeForSamenessCheck)(tag, subfieldCode, value);
|
|
202
|
-
|
|
203
|
-
/* eslint-enable */
|
|
133
|
+
value = value.replace(/(\S)(?:,|\.|\?|!|\. -| *:| *;| =| \/)$/u, "$1");
|
|
134
|
+
value = value.replace(/^\(([^()]+)\)$/u, "$1");
|
|
135
|
+
value = value.replace(/^\[([^[\]]+)\]$/u, "$1");
|
|
136
|
+
value = removeCopyright(value);
|
|
137
|
+
value = value.replace(/http:\/\//ug, "https://");
|
|
138
|
+
value = normalizeForSamenessCheck(tag, subfieldCode, value);
|
|
204
139
|
return value;
|
|
205
140
|
}
|
|
206
141
|
function uniqueKeyMatches(baseField, sourceField, forcedKeyString = null) {
|
|
207
|
-
|
|
208
|
-
// What to do if if base
|
|
209
|
-
// const keySubfieldsAsString = forcedKeyString || getUniqueKeyFields(field1);
|
|
210
|
-
const keySubfieldsAsString = forcedKeyString || (0, _mergeConstraints.getMergeConstraintsForTag)(baseField.tag, 'key');
|
|
211
|
-
//return mandatorySubfieldComparison(baseField, sourceField, keySubfieldsAsString);
|
|
142
|
+
const keySubfieldsAsString = forcedKeyString || getMergeConstraintsForTag(baseField.tag, "key");
|
|
212
143
|
return optionalSubfieldComparison(baseField, sourceField, keySubfieldsAsString);
|
|
213
144
|
}
|
|
214
145
|
function optionalSubfieldComparison(originalBaseField, originalSourceField, keySubfieldsAsString) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
// We use clones here, since these changes done below are not intented to appear on the actual records.
|
|
218
|
-
const field1 = (0, _normalizeFieldForComparison.cloneAndNormalizeFieldForComparison)(originalBaseField);
|
|
219
|
-
const field2 = (0, _normalizeFieldForComparison.cloneAndNormalizeFieldForComparison)(originalSourceField);
|
|
146
|
+
const field1 = cloneAndNormalizeFieldForComparison(originalBaseField);
|
|
147
|
+
const field2 = cloneAndNormalizeFieldForComparison(originalSourceField);
|
|
220
148
|
if (keySubfieldsAsString === null) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
// (However, keySubfieldsAsString === '' will always succeed. Used by 040 at least.)
|
|
226
|
-
// NB! substring(6) skips "TAG II" (I=indicator. Thus we skip indicators)
|
|
227
|
-
return (0, _utils.fieldToString)(field1).substring(6) === (0, _utils.fieldToString)(field2).substring(6);
|
|
228
|
-
}
|
|
229
|
-
const subfieldArray = keySubfieldsAsString.split('');
|
|
230
|
-
|
|
231
|
-
// Long forgotten, but my educated guess about this: if 'key' is defined in merge constraints
|
|
232
|
-
// for this field, then at least one of the subfield codes in 'key' must be present in both fields.
|
|
233
|
-
// However, this is not necessarily right.
|
|
234
|
-
if (subfieldArray.length > 0 && !subfieldArray.some(sfCode => hasCommonNominator(sfCode))) {
|
|
149
|
+
return fieldToString(field1).substring(6) === fieldToString(field2).substring(6);
|
|
150
|
+
}
|
|
151
|
+
const subfieldArray = keySubfieldsAsString.split("");
|
|
152
|
+
if (subfieldArray.length > 0 && !subfieldArray.some((sfCode) => hasCommonNominator(sfCode))) {
|
|
235
153
|
return false;
|
|
236
154
|
}
|
|
237
|
-
return subfieldArray.every(subfieldCode => testOptionalSubfield(originalBaseField.tag, subfieldCode));
|
|
155
|
+
return subfieldArray.every((subfieldCode) => testOptionalSubfield(originalBaseField.tag, subfieldCode));
|
|
238
156
|
function hasCommonNominator(subfieldCode) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// If base has $a and source has $b, there's no common nominator, thus fail...
|
|
242
|
-
const subfields1 = field1.subfields.filter(subfield => subfield.code === subfieldCode && (0, _worldKnowledge.valueCarriesMeaning)(field1.tag, subfield.code, subfield.value));
|
|
243
|
-
const subfields2 = field2.subfields.filter(subfield => subfield.code === subfieldCode && (0, _worldKnowledge.valueCarriesMeaning)(field2.tag, subfield.code, subfield.value));
|
|
157
|
+
const subfields1 = field1.subfields.filter((subfield) => subfield.code === subfieldCode && valueCarriesMeaning(field1.tag, subfield.code, subfield.value));
|
|
158
|
+
const subfields2 = field2.subfields.filter((subfield) => subfield.code === subfieldCode && valueCarriesMeaning(field2.tag, subfield.code, subfield.value));
|
|
244
159
|
return subfields1.length > 0 && subfields2.length > 0;
|
|
245
160
|
}
|
|
246
161
|
function testOptionalSubfield(tag, subfieldCode) {
|
|
247
|
-
|
|
248
|
-
const
|
|
249
|
-
const subfields2 = field2.subfields.filter(subfield => subfield.code === subfieldCode && (0, _worldKnowledge.valueCarriesMeaning)(field2.tag, subfield.code, subfield.value));
|
|
250
|
-
|
|
251
|
-
// If one side is empty, all is good
|
|
162
|
+
const subfields1 = field1.subfields.filter((subfield) => subfield.code === subfieldCode && valueCarriesMeaning(field1.tag, subfield.code, subfield.value));
|
|
163
|
+
const subfields2 = field2.subfields.filter((subfield) => subfield.code === subfieldCode && valueCarriesMeaning(field2.tag, subfield.code, subfield.value));
|
|
252
164
|
if (subfields1.length === 0 || subfields2.length === 0) {
|
|
253
165
|
return true;
|
|
254
166
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// When pairing we can use stronger normalizations than the generic one:
|
|
260
|
-
const subfieldValues1 = subfields1.map(sf => counterpartExtraNormalize(tag, subfieldCode, sf.value));
|
|
261
|
-
const subfieldValues2 = subfields2.map(sf => counterpartExtraNormalize(tag, subfieldCode, sf.value));
|
|
262
|
-
|
|
263
|
-
//nvdebug(`SF1 NORM: ${subfieldValues1.join(' --')}`, debugDev);
|
|
264
|
-
//nvdebug(`SF2 NORM: ${subfieldValues2.join(' --')}`, debugDev);
|
|
265
|
-
|
|
266
|
-
// If one set is a subset of the other, all is probably good (how about 653$a, 505...)
|
|
267
|
-
if (subfieldValues1.every(val => subfieldValues2.includes(val)) || subfieldValues2.every(val => subfieldValues1.includes(val))) {
|
|
167
|
+
const subfieldValues1 = subfields1.map((sf) => counterpartExtraNormalize(tag, subfieldCode, sf.value));
|
|
168
|
+
const subfieldValues2 = subfields2.map((sf) => counterpartExtraNormalize(tag, subfieldCode, sf.value));
|
|
169
|
+
if (subfieldValues1.every((val) => subfieldValues2.includes(val)) || subfieldValues2.every((val) => subfieldValues1.includes(val))) {
|
|
268
170
|
return true;
|
|
269
171
|
}
|
|
270
172
|
if (subfieldValues1.length === 1 && subfieldValues2.length === 1) {
|
|
271
|
-
return pairableValue(field1.tag, subfieldCode, subfieldValues1[0], subfieldValues2[0]) !==
|
|
173
|
+
return pairableValue(field1.tag, subfieldCode, subfieldValues1[0], subfieldValues2[0]) !== void 0;
|
|
272
174
|
}
|
|
273
175
|
return false;
|
|
274
176
|
}
|
|
275
177
|
}
|
|
276
178
|
function mandatorySubfieldComparison(originalField1, originalField2, keySubfieldsAsString) {
|
|
277
|
-
|
|
278
|
-
const
|
|
279
|
-
const field2 = (0, _normalizeFieldForComparison.cloneAndNormalizeFieldForComparison)(originalField2);
|
|
179
|
+
const field1 = cloneAndNormalizeFieldForComparison(originalField1);
|
|
180
|
+
const field2 = cloneAndNormalizeFieldForComparison(originalField2);
|
|
280
181
|
if (keySubfieldsAsString === null) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
// (However, keySubfieldsAsString === '' will always succeed. Used by 040 at least.)
|
|
286
|
-
return (0, _utils.fieldToString)(field1) === (0, _utils.fieldToString)(field2);
|
|
287
|
-
}
|
|
288
|
-
const subfieldArray = keySubfieldsAsString.split('');
|
|
289
|
-
|
|
290
|
-
//const differentSubfieldCodes = differentPublisherSubfields(originalField1, originalField2);
|
|
291
|
-
|
|
292
|
-
return subfieldArray.every(subfieldCode => mandatorySingleSubfieldComparison(subfieldCode));
|
|
182
|
+
return fieldToString(field1) === fieldToString(field2);
|
|
183
|
+
}
|
|
184
|
+
const subfieldArray = keySubfieldsAsString.split("");
|
|
185
|
+
return subfieldArray.every((subfieldCode) => mandatorySingleSubfieldComparison(subfieldCode));
|
|
293
186
|
function mandatorySingleSubfieldComparison(subfieldCode) {
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
const subfieldValues2 = field2.subfields.filter(subfield => subfield.code === subfieldCode).map(sf => sf.value);
|
|
297
|
-
// Assume that at least 1 instance must exist and that all instances must match
|
|
187
|
+
const subfieldValues1 = field1.subfields.filter((subfield) => subfield.code === subfieldCode).map((sf) => sf.value);
|
|
188
|
+
const subfieldValues2 = field2.subfields.filter((subfield) => subfield.code === subfieldCode).map((sf) => sf.value);
|
|
298
189
|
if (subfieldValues1.length !== subfieldValues2.length) {
|
|
299
190
|
debugDev(`mSC: Unique key: subfield ${subfieldCode} issues...`);
|
|
300
191
|
return false;
|
|
301
192
|
}
|
|
302
|
-
return subfieldValues1.every(value => subfieldValues2.includes(value));
|
|
193
|
+
return subfieldValues1.every((value) => subfieldValues2.includes(value));
|
|
303
194
|
}
|
|
304
195
|
}
|
|
305
196
|
function tagToRegexp(tag, internalMerge = false) {
|
|
@@ -307,63 +198,57 @@ function tagToRegexp(tag, internalMerge = false) {
|
|
|
307
198
|
return counterpartRegexpsSingle[tag];
|
|
308
199
|
}
|
|
309
200
|
if (!internalMerge && tag in counterpartRegexps) {
|
|
310
|
-
// eg. 700 looks for tag /^[17]00$/...
|
|
311
201
|
const regexp = counterpartRegexps[tag];
|
|
312
|
-
//nvdebug(`regexp for ${tag} found: ${regexp}`, debugDev);
|
|
313
202
|
return regexp;
|
|
314
203
|
}
|
|
315
|
-
|
|
316
|
-
return new RegExp(`^${tag}$`, 'u');
|
|
204
|
+
return new RegExp(`^${tag}$`, "u");
|
|
317
205
|
}
|
|
318
206
|
function areRequiredSubfieldsPresent(field) {
|
|
319
|
-
const subfieldString =
|
|
207
|
+
const subfieldString = getMergeConstraintsForTag(field.tag, "required");
|
|
320
208
|
if (subfieldString === null) {
|
|
321
209
|
return true;
|
|
322
|
-
}
|
|
323
|
-
const subfieldArray = subfieldString.split(
|
|
324
|
-
return subfieldArray.every(sfcode => {
|
|
325
|
-
const result =
|
|
210
|
+
}
|
|
211
|
+
const subfieldArray = subfieldString.split("");
|
|
212
|
+
return subfieldArray.every((sfcode) => {
|
|
213
|
+
const result = fieldHasSubfield(field, sfcode);
|
|
326
214
|
if (!result) {
|
|
327
|
-
debugDev(`Required subfield
|
|
215
|
+
debugDev(`Required subfield \u2021${sfcode} not found in '${fieldToString(field)}'!`);
|
|
328
216
|
return false;
|
|
329
217
|
}
|
|
330
218
|
return true;
|
|
331
219
|
});
|
|
332
220
|
}
|
|
333
221
|
function arePairedSubfieldsInBalance(field1, field2) {
|
|
334
|
-
const subfieldString =
|
|
222
|
+
const subfieldString = getMergeConstraintsForTag(field1.tag, "paired");
|
|
335
223
|
if (subfieldString === null) {
|
|
336
224
|
return true;
|
|
337
225
|
}
|
|
338
|
-
const subfieldArray = subfieldString.split(
|
|
339
|
-
return subfieldArray.every(sfcode =>
|
|
226
|
+
const subfieldArray = subfieldString.split("");
|
|
227
|
+
return subfieldArray.every((sfcode) => fieldHasNSubfields(field1, sfcode) === fieldHasNSubfields(field2, sfcode));
|
|
340
228
|
}
|
|
341
229
|
function syntacticallyMergablePair(baseField, sourceField, config) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
(0, _utils.nvdebug)(`non-mergable (reason: indicator1): ${JSON.stringify(config)}`, debugDev);
|
|
230
|
+
if (!mergableIndicator1(baseField, sourceField, config)) {
|
|
231
|
+
nvdebug(`non-mergable (reason: indicator1): ${JSON.stringify(config)}`, debugDev);
|
|
345
232
|
return false;
|
|
346
233
|
}
|
|
347
|
-
if (!
|
|
348
|
-
|
|
234
|
+
if (!mergableIndicator2(baseField, sourceField, config)) {
|
|
235
|
+
nvdebug(`non-mergable (reason: indicator2): ${JSON.stringify(config)}`, debugDev);
|
|
349
236
|
return false;
|
|
350
237
|
}
|
|
351
|
-
if (!
|
|
352
|
-
|
|
238
|
+
if (!controlSubfieldsPermitMerge(baseField, sourceField)) {
|
|
239
|
+
nvdebug("non-mergable (reason: control subfield)", debugDev);
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
if (!provenanceSubfieldsPermitMerge(baseField, sourceField)) {
|
|
243
|
+
nvdebug("non-mergable (reason: data provenance subfield)", debugDev);
|
|
353
244
|
return false;
|
|
354
245
|
}
|
|
355
|
-
|
|
356
|
-
// NB! field1.tag and field2.tag might differ (1XX vs 7XX). Therefore required subfields might theoretically differ as well.
|
|
357
|
-
// Note: Theoretically 260 $efg vs 264 with IND2=3 has already been handled by the preprocessor.
|
|
358
|
-
// Thus check both:
|
|
359
246
|
if (!areRequiredSubfieldsPresent(baseField) || !areRequiredSubfieldsPresent(sourceField)) {
|
|
360
|
-
|
|
247
|
+
nvdebug("non-mergable (reason: missing subfields)", debugDev);
|
|
361
248
|
return false;
|
|
362
249
|
}
|
|
363
|
-
|
|
364
|
-
// Stuff of Hacks! Eg. require that both fields either have or have not X00$t:
|
|
365
250
|
if (!arePairedSubfieldsInBalance(baseField, sourceField)) {
|
|
366
|
-
|
|
251
|
+
nvdebug("required subfield pair check failed.", debugDev);
|
|
367
252
|
return false;
|
|
368
253
|
}
|
|
369
254
|
return true;
|
|
@@ -372,20 +257,16 @@ function mergablePair(baseField, sourceField, config) {
|
|
|
372
257
|
if (!syntacticallyMergablePair(baseField, sourceField, config)) {
|
|
373
258
|
return false;
|
|
374
259
|
}
|
|
375
|
-
|
|
376
|
-
//debug('Test semantics...');
|
|
377
260
|
if (!semanticallyMergablePair(baseField, sourceField)) {
|
|
378
|
-
|
|
261
|
+
nvdebug("non-mergable (reason: semantics)", debugDev);
|
|
379
262
|
return false;
|
|
380
263
|
}
|
|
381
|
-
|
|
264
|
+
nvdebug(`MERGABLE PAIR:
|
|
265
|
+
B: ${fieldToString(baseField)}
|
|
266
|
+
S: ${fieldToString(sourceField)}`, debugDev);
|
|
382
267
|
return true;
|
|
383
268
|
}
|
|
384
269
|
function pairableAsteriIDs(baseField, sourceField) {
|
|
385
|
-
//nvdebug(`ASTERI1 ${fieldToString(baseField)}`, debugDev); // eslint-disable-line
|
|
386
|
-
//nvdebug(`ASTERI2 ${fieldToString(sourceField)}`, debugDev); // eslint-disable-line
|
|
387
|
-
|
|
388
|
-
// Check that relevant control subfield(s) exist in both records (as controlSubfieldsPermitMerge() doesn't check it):
|
|
389
270
|
const fin11a = getAsteriIDs(baseField);
|
|
390
271
|
if (fin11a.length === 0) {
|
|
391
272
|
return false;
|
|
@@ -394,96 +275,66 @@ function pairableAsteriIDs(baseField, sourceField) {
|
|
|
394
275
|
if (fin11b.length === 0) {
|
|
395
276
|
return false;
|
|
396
277
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
// Check that found control subfields agree. Use pre-existing generic function to reduce code.
|
|
400
|
-
// (NB! We could optimize and just return true here, as control subfield check is done elsewhere as well.
|
|
401
|
-
// However, explicitly checking them here makes the code more robust.)
|
|
402
|
-
if (!(0, _controlSubfields.controlSubfieldsPermitMerge)(baseField, sourceField)) {
|
|
278
|
+
if (!controlSubfieldsPermitMerge(baseField, sourceField)) {
|
|
403
279
|
return false;
|
|
404
280
|
}
|
|
405
|
-
//console.log(`ASTERI PAIR ${fieldToString(sourceField)}`); // eslint-disable-line
|
|
406
281
|
return true;
|
|
407
|
-
|
|
408
|
-
// NB! This boldly assumes that the default prefix for Asteri is '(FIN11)', not '(FI-ASTERI-N)' nor a finaf urn...
|
|
409
282
|
function getAsteriIDs(field) {
|
|
410
|
-
return field.subfields.filter(sf => sf.code ===
|
|
283
|
+
return field.subfields.filter((sf) => sf.code === "0").map((sf) => normalizeControlSubfieldValue(sf.value)).filter((val) => val.substring(0, 7) === "(FIN11)");
|
|
411
284
|
}
|
|
412
285
|
}
|
|
413
286
|
function hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(field) {
|
|
414
|
-
if (field.tag ===
|
|
415
|
-
return [
|
|
287
|
+
if (field.tag === "260" || field.tag === "264") {
|
|
288
|
+
return ["a", "b", "c", "e", "f", "g"].some((subfieldCode) => fieldHasMultipleSubfields(field, subfieldCode));
|
|
416
289
|
}
|
|
417
|
-
if (field.tag ===
|
|
418
|
-
return [
|
|
290
|
+
if (field.tag === "382") {
|
|
291
|
+
return ["a", "b", "d", "e", "n", "p"].some((subfieldCode) => fieldHasMultipleSubfields(field, subfieldCode));
|
|
419
292
|
}
|
|
420
|
-
if (field.tag ===
|
|
421
|
-
return [
|
|
293
|
+
if (field.tag === "505") {
|
|
294
|
+
return ["t", "r", "g"].some((subfieldCode) => fieldHasMultipleSubfields(field, subfieldCode));
|
|
422
295
|
}
|
|
423
296
|
return false;
|
|
424
297
|
}
|
|
425
298
|
function pairableName(baseField, sourceField) {
|
|
426
|
-
// 100$a$t: remove $t and everything after that
|
|
427
299
|
const reducedField1 = fieldToNamePart(baseField);
|
|
428
300
|
const reducedField2 = fieldToNamePart(sourceField);
|
|
429
|
-
const string1 =
|
|
430
|
-
const string2 =
|
|
431
|
-
|
|
432
|
-
//nvdebug(`IN: pairableName():\n '${string1}' vs\n '${string2}'`, debugDev);
|
|
301
|
+
const string1 = fieldToString(reducedField1);
|
|
302
|
+
const string2 = fieldToString(reducedField2);
|
|
433
303
|
if (string1 === string2) {
|
|
434
304
|
return true;
|
|
435
305
|
}
|
|
436
|
-
|
|
437
|
-
// Essentially these are too hard to handle with field-merge (eg. multi-505$g)
|
|
438
306
|
if (hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(reducedField1) || hasRepeatableSubfieldThatShouldBeTreatedAsNonRepeatable(reducedField2)) {
|
|
439
307
|
return false;
|
|
440
308
|
}
|
|
441
|
-
|
|
442
|
-
// Compare the remaining subsets...
|
|
443
|
-
// First check that name matches...
|
|
444
309
|
if (uniqueKeyMatches(reducedField1, reducedField2)) {
|
|
445
|
-
|
|
310
|
+
nvdebug(` name match: '${fieldToString(reducedField1)}'`, debugDev);
|
|
446
311
|
return true;
|
|
447
312
|
}
|
|
448
|
-
|
|
449
|
-
// However, name mismatch is not critical! If Asteri ID matches, it's still a match! *NOT* sure whether this a good idea.
|
|
450
|
-
// 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.
|
|
451
|
-
// 2023-03-07: Enable this again!
|
|
452
313
|
if (pairableAsteriIDs(baseField, sourceField)) {
|
|
453
|
-
//nvdebug(` name match based on ASTERI $0'`, debugDev);
|
|
454
314
|
return true;
|
|
455
315
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
316
|
+
nvdebug(` name mismatch:`, debugDev);
|
|
317
|
+
nvdebug(` '${fieldToString(reducedField1)}' vs`, debugDev);
|
|
318
|
+
nvdebug(` '${fieldToString(reducedField2)}'`, debugDev);
|
|
459
319
|
return false;
|
|
460
320
|
}
|
|
461
321
|
function semanticallyMergablePair(baseField, sourceField) {
|
|
462
|
-
// On rare occasions a field contains also a title part. For these name part (= normally everything) and title part
|
|
463
|
-
// must be checked separately:
|
|
464
322
|
if (!titlePartsMatch(baseField, sourceField)) {
|
|
465
|
-
|
|
323
|
+
nvdebug(` ${baseField.tag} is unmergable: Title part mismatch.`, debugDev);
|
|
466
324
|
return false;
|
|
467
325
|
}
|
|
468
|
-
|
|
469
|
-
// Hmm... we should check lifespan here, $d YYYY
|
|
470
|
-
|
|
471
|
-
// Handle the field specific "unique key" (=set of fields that make the field unique
|
|
472
326
|
if (!pairableName(baseField, sourceField)) {
|
|
473
|
-
|
|
327
|
+
nvdebug("Unmergable: Name part mismatch", debugDev);
|
|
474
328
|
return false;
|
|
475
329
|
}
|
|
476
|
-
//debug(' Semantic checks passed! We are MERGABLE!');
|
|
477
|
-
|
|
478
330
|
return true;
|
|
479
331
|
}
|
|
480
332
|
function namePartThreshold(field) {
|
|
481
|
-
// Threshold is only applicaple to some tags..
|
|
482
333
|
if (!/[10]0$/u.test(field.tag)) {
|
|
483
334
|
return -1;
|
|
484
335
|
}
|
|
485
|
-
const t = field.subfields.findIndex(currSubfield => currSubfield.code ===
|
|
486
|
-
const u = t;
|
|
336
|
+
const t = field.subfields.findIndex((currSubfield) => currSubfield.code === "t");
|
|
337
|
+
const u = t;
|
|
487
338
|
if (t === -1) {
|
|
488
339
|
return u;
|
|
489
340
|
}
|
|
@@ -494,41 +345,21 @@ function namePartThreshold(field) {
|
|
|
494
345
|
}
|
|
495
346
|
function fieldToNamePart(field) {
|
|
496
347
|
const index = namePartThreshold(field);
|
|
497
|
-
const relevantSubfields = field.subfields.filter((sf, i) => i < index || index === -1).filter(sf => !irrelevantSubfieldsInNameAndTitlePartComparison.includes(sf.code));
|
|
498
|
-
const subsetField = {
|
|
499
|
-
'tag': field.tag,
|
|
500
|
-
'ind1': field.ind1,
|
|
501
|
-
'ind2': field.ind2,
|
|
502
|
-
subfields: relevantSubfields
|
|
503
|
-
};
|
|
504
|
-
|
|
505
|
-
/*
|
|
506
|
-
if (index > -1) {
|
|
507
|
-
debugDev(`Name subset: ${fieldToString(subsetField)}`);
|
|
508
|
-
}
|
|
509
|
-
*/
|
|
510
|
-
|
|
511
|
-
// Ummm... Sometimes $0 comes after $t but belongs to name part
|
|
512
|
-
|
|
348
|
+
const relevantSubfields = field.subfields.filter((sf, i) => i < index || index === -1).filter((sf) => !irrelevantSubfieldsInNameAndTitlePartComparison.includes(sf.code));
|
|
349
|
+
const subsetField = { "tag": field.tag, "ind1": field.ind1, "ind2": field.ind2, subfields: relevantSubfields };
|
|
513
350
|
return subsetField;
|
|
514
351
|
}
|
|
515
352
|
function fieldToTitlePart(field) {
|
|
516
|
-
|
|
517
|
-
const
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
'tag': field.tag,
|
|
521
|
-
'ind1': field.ind1,
|
|
522
|
-
'ind2': field.ind2,
|
|
523
|
-
subfields: relevantSubfields
|
|
524
|
-
};
|
|
525
|
-
debugDev(`Title subset: ${(0, _utils.fieldToString)(subsetField)}`);
|
|
353
|
+
const index = field.subfields.findIndex((currSubfield) => currSubfield.code === "t");
|
|
354
|
+
const relevantSubfields = field.subfields.filter((sf, i) => i >= index).filter((sf) => !irrelevantSubfieldsInNameAndTitlePartComparison.includes(sf.code));
|
|
355
|
+
const subsetField = { "tag": field.tag, "ind1": field.ind1, "ind2": field.ind2, subfields: relevantSubfields };
|
|
356
|
+
debugDev(`Title subset: ${fieldToString(subsetField)}`);
|
|
526
357
|
return subsetField;
|
|
527
358
|
}
|
|
528
359
|
function containsTitlePart(field) {
|
|
529
|
-
return fieldCanHaveTitlePart(field) &&
|
|
530
|
-
function fieldCanHaveTitlePart(
|
|
531
|
-
return [
|
|
360
|
+
return fieldCanHaveTitlePart(field) && fieldHasSubfield(field, "t");
|
|
361
|
+
function fieldCanHaveTitlePart(field2) {
|
|
362
|
+
return ["100", "110", "111", "700", "710", "711"].includes(field2.tag);
|
|
532
363
|
}
|
|
533
364
|
}
|
|
534
365
|
function titlePartsMatch(field1, field2) {
|
|
@@ -539,43 +370,38 @@ function titlePartsMatch(field1, field2) {
|
|
|
539
370
|
return false;
|
|
540
371
|
}
|
|
541
372
|
debugDev(`TITLE PARTS NEED TO BE COMPARED`);
|
|
542
|
-
|
|
543
|
-
// 100$a$t: remove $t and everything after that
|
|
544
373
|
const subset1 = fieldToTitlePart(field1);
|
|
545
374
|
const subset2 = fieldToTitlePart(field2);
|
|
546
|
-
|
|
547
|
-
return mandatorySubfieldComparison(subset1, subset2, 'dfhklmnoprstxvg');
|
|
375
|
+
return mandatorySubfieldComparison(subset1, subset2, "dfhklmnoprstxvg");
|
|
548
376
|
}
|
|
549
377
|
function getAlternativeNamesFrom9XX(record, field) {
|
|
550
|
-
// Should we support 6XX and 8XX as well? Prolly not...
|
|
551
378
|
if (!field.tag.match(/^(?:100|110|111|600|610|611|700|710|711)$/u)) {
|
|
552
379
|
return [];
|
|
553
380
|
}
|
|
554
381
|
const tag = `9${field.tag.substring(1)}`;
|
|
555
|
-
const cands = record.get(tag).filter(f =>
|
|
382
|
+
const cands = record.get(tag).filter((f) => fieldHasSubfield(f, "a") && fieldHasSubfield(f, "y"));
|
|
556
383
|
if (cands.length === 0) {
|
|
557
384
|
return [];
|
|
558
385
|
}
|
|
559
|
-
const punctuationlessField =
|
|
560
|
-
const [name] = punctuationlessField.subfields.filter(sf => sf.code ===
|
|
561
|
-
return cands.map(candField => getAltName(candField)).filter(val => val !==
|
|
386
|
+
const punctuationlessField = cloneAndRemovePunctuation(field);
|
|
387
|
+
const [name] = punctuationlessField.subfields.filter((sf) => sf.code === "a").map((sf) => sf.value);
|
|
388
|
+
return cands.map((candField) => getAltName(candField)).filter((val) => val !== void 0);
|
|
562
389
|
function getAltName(altField) {
|
|
563
|
-
const [altA] = altField.subfields.filter(sf => sf.code ===
|
|
564
|
-
const [altY] = altField.subfields.filter(sf => sf.code ===
|
|
565
|
-
|
|
390
|
+
const [altA] = altField.subfields.filter((sf) => sf.code === "a").map((sf) => sf.value);
|
|
391
|
+
const [altY] = altField.subfields.filter((sf) => sf.code === "y").map((sf) => sf.value);
|
|
392
|
+
nvdebug(`Compare '${name}' vs '${altA}'/'${altY}'`, debugDev);
|
|
566
393
|
if (name === altA) {
|
|
567
394
|
return altY;
|
|
568
395
|
}
|
|
569
396
|
if (name === altY) {
|
|
570
397
|
return altA;
|
|
571
398
|
}
|
|
572
|
-
|
|
573
|
-
return
|
|
399
|
+
nvdebug(` miss`, debugDev);
|
|
400
|
+
return void 0;
|
|
574
401
|
}
|
|
575
402
|
}
|
|
576
403
|
function mergablePairWithAltName(normCandField, normalizedField, altName, config) {
|
|
577
|
-
|
|
578
|
-
const [a] = normalizedField.subfields.filter(sf => sf.code === 'a');
|
|
404
|
+
const [a] = normalizedField.subfields.filter((sf) => sf.code === "a");
|
|
579
405
|
if (!a) {
|
|
580
406
|
return false;
|
|
581
407
|
}
|
|
@@ -583,90 +409,72 @@ function mergablePairWithAltName(normCandField, normalizedField, altName, config
|
|
|
583
409
|
return mergablePair(normCandField, normalizedField, config);
|
|
584
410
|
}
|
|
585
411
|
function getCounterpartIndex(field, counterpartCands, altNames, config) {
|
|
586
|
-
const normalizedField =
|
|
587
|
-
const normalizedCounterpartCands = counterpartCands.map(f =>
|
|
588
|
-
const index = normalizedCounterpartCands.findIndex(normCandField => mergablePair(normCandField, normalizedField, config));
|
|
412
|
+
const normalizedField = cloneAndNormalizeFieldForComparison(field);
|
|
413
|
+
const normalizedCounterpartCands = counterpartCands.map((f) => cloneAndNormalizeFieldForComparison(f));
|
|
414
|
+
const index = normalizedCounterpartCands.findIndex((normCandField) => mergablePair(normCandField, normalizedField, config));
|
|
589
415
|
if (index > -1) {
|
|
590
416
|
return index;
|
|
591
417
|
}
|
|
592
|
-
return normalizedCounterpartCands.findIndex(normCandField => altNames.some(altName => mergablePairWithAltName(normCandField, normalizedField, altName, config)));
|
|
418
|
+
return normalizedCounterpartCands.findIndex((normCandField) => altNames.some((altName) => mergablePairWithAltName(normCandField, normalizedField, altName, config)));
|
|
593
419
|
}
|
|
594
420
|
function field264Exception(baseField, sourceRecord, sourceField, config) {
|
|
595
|
-
|
|
596
|
-
if (baseField.tag !==
|
|
421
|
+
nvdebug("Field 264 exception as per MET-456", debugDev);
|
|
422
|
+
if (baseField.tag !== "264") {
|
|
597
423
|
return false;
|
|
598
424
|
}
|
|
599
|
-
if (sourceField.tag !==
|
|
425
|
+
if (sourceField.tag !== "264" || sourceRecord.get("264").length !== 1) {
|
|
600
426
|
return false;
|
|
601
427
|
}
|
|
602
|
-
|
|
603
|
-
// Don't worry about semantics:
|
|
604
428
|
return syntacticallyMergablePair(sourceField, baseField, config);
|
|
605
429
|
}
|
|
606
430
|
function getCounterpartCandidates(field, record) {
|
|
607
431
|
const counterpartCands = record.get(tagToRegexp(field.tag, record.internalMerge));
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
if (field.tag === '260' && isNotCopyrightYear(field)) {
|
|
611
|
-
return counterpartCands.filter(candField => !isCopyrightField264(candField));
|
|
432
|
+
if (field.tag === "260" && isNotCopyrightYear(field)) {
|
|
433
|
+
return counterpartCands.filter((candField) => !isCopyrightField264(candField));
|
|
612
434
|
}
|
|
613
|
-
if (field.tag ===
|
|
614
|
-
|
|
615
|
-
return counterpartCands.filter(candField => !isNotCopyrightYear(candField));
|
|
435
|
+
if (field.tag === "264" && isCopyrightField264(field)) {
|
|
436
|
+
return counterpartCands.filter((candField) => !isNotCopyrightYear(candField));
|
|
616
437
|
}
|
|
617
|
-
function isCopyrightField264(
|
|
618
|
-
return
|
|
438
|
+
function isCopyrightField264(field2) {
|
|
439
|
+
return field2.tag === "264" && field2.ind2 === "4";
|
|
619
440
|
}
|
|
620
|
-
function isNotCopyrightYear(
|
|
621
|
-
if (
|
|
622
|
-
return !isCopyrightField264(
|
|
441
|
+
function isNotCopyrightYear(field2) {
|
|
442
|
+
if (field2.tag === "264") {
|
|
443
|
+
return !isCopyrightField264(field2);
|
|
623
444
|
}
|
|
624
|
-
|
|
625
|
-
return !field.subfields.some(sf => sf.code === 'a' && sf.code === 'b');
|
|
445
|
+
return !field2.subfields.some((sf) => sf.code === "a" && sf.code === "b");
|
|
626
446
|
}
|
|
627
447
|
return counterpartCands;
|
|
628
448
|
}
|
|
629
|
-
function baseIsSource(base, source) {
|
|
449
|
+
export function baseIsSource(base, source) {
|
|
630
450
|
base.localTest = true;
|
|
631
451
|
const result = source.localTest;
|
|
632
452
|
delete base.localTest;
|
|
633
453
|
return result;
|
|
634
454
|
}
|
|
635
|
-
function getCounterpart(baseRecord, sourceRecord, field, config) {
|
|
636
|
-
|
|
637
|
-
// (<= Note that self-merge behaves differently from two records here.)
|
|
638
|
-
// Hacks: 973 can merge with 773, 940 can merge with 240 (but not the other way around)
|
|
639
|
-
//nvdebug(`COUNTERPART FOR '${fieldToString(field)}'?`, debugDev);
|
|
640
|
-
const counterpartCands = getCounterpartCandidates(field, baseRecord).filter(f => !f.mergeCandidate);
|
|
455
|
+
export function getCounterpart(baseRecord, sourceRecord, field, config) {
|
|
456
|
+
const counterpartCands = getCounterpartCandidates(field, baseRecord).filter((f) => !f.mergeCandidate);
|
|
641
457
|
if (!counterpartCands || counterpartCands.length === 0) {
|
|
642
|
-
//nvdebug(`No counterpart(s) found for ${fieldToString(field)}`, debugDev);
|
|
643
458
|
return null;
|
|
644
459
|
}
|
|
645
|
-
|
|
646
|
-
const normalizedField =
|
|
647
|
-
|
|
648
|
-
(0, _utils.nvdebug)(`Norm to: '${(0, _utils.fieldToString)(normalizedField)}'`, debugDev);
|
|
460
|
+
nvdebug(`Compare incoming '${fieldToString(field)}' with (up to) ${counterpartCands.length} existing field(s)`, debugDev);
|
|
461
|
+
const normalizedField = cloneAndNormalizeFieldForComparison(field);
|
|
462
|
+
nvdebug(`Norm to: '${fieldToString(normalizedField)}'`, debugDev);
|
|
649
463
|
const uniqueAlternativeNames = getUniqueAlernativeNames();
|
|
650
464
|
function getUniqueAlernativeNames() {
|
|
651
465
|
if (baseIsSource(baseRecord, sourceRecord)) {
|
|
652
466
|
return [];
|
|
653
467
|
}
|
|
654
|
-
// Try to look for alternative names from base and source record's 9XX fields:
|
|
655
468
|
const alternativeNames = getAlternativeNamesFrom9XX(baseRecord, field).concat(getAlternativeNamesFrom9XX(sourceRecord, field));
|
|
656
469
|
return alternativeNames.filter((name, i) => alternativeNames.indexOf(name) === i);
|
|
657
470
|
}
|
|
658
|
-
|
|
659
|
-
//nvdebug(` S: ${fieldToString(normalizedField)}`, debugDev);
|
|
660
|
-
// Then find (the index of) the first mathing candidate field and return it.
|
|
661
471
|
const index = getCounterpartIndex(normalizedField, counterpartCands, uniqueAlternativeNames, config);
|
|
662
472
|
if (index > -1) {
|
|
663
473
|
return counterpartCands[index];
|
|
664
474
|
}
|
|
665
|
-
|
|
666
|
-
// MET-456 exception
|
|
667
475
|
if (counterpartCands.length === 1 && field264Exception(counterpartCands[0], sourceRecord, field, config)) {
|
|
668
476
|
return counterpartCands[0];
|
|
669
477
|
}
|
|
670
478
|
return null;
|
|
671
479
|
}
|
|
672
|
-
//# sourceMappingURL=counterpartField.js.map
|
|
480
|
+
//# sourceMappingURL=counterpartField.js.map
|