@natlibfi/marc-record-validators-melinda 12.0.7 → 12.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addMissingField041.js +6 -3
- package/dist/addMissingField041.js.map +2 -2
- package/dist/addMissingField336.js +7 -4
- package/dist/addMissingField336.js.map +2 -2
- package/dist/addMissingField337.js +6 -3
- package/dist/addMissingField337.js.map +2 -2
- package/dist/addMissingField338.js +8 -5
- package/dist/addMissingField338.js.map +2 -2
- package/dist/cyrillux-usemarcon-replacement.js +5 -2
- package/dist/cyrillux-usemarcon-replacement.js.map +2 -2
- package/dist/cyrillux.js +10 -7
- package/dist/cyrillux.js.map +2 -2
- package/dist/disambiguateSeriesStatements.js +2 -1
- package/dist/disambiguateSeriesStatements.js.map +2 -2
- package/dist/drop-terms.js +5 -4
- package/dist/drop-terms.js.map +2 -2
- package/dist/fix-33X.js +7 -4
- package/dist/fix-33X.js.map +2 -2
- package/dist/fix-country-codes.js +5 -0
- package/dist/fix-country-codes.js.map +2 -2
- package/dist/fix-language-codes.js +5 -1
- package/dist/fix-language-codes.js.map +2 -2
- package/dist/fix-sami-041.js +11 -10
- package/dist/fix-sami-041.js.map +2 -2
- package/dist/indicator-fixes.js +5 -1
- package/dist/indicator-fixes.js.map +2 -2
- package/dist/merge-fields/counterpartField.js +6 -6
- package/dist/merge-fields/counterpartField.js.map +2 -2
- package/dist/merge-fields/mergableIndicator.js +0 -3
- package/dist/merge-fields/mergableIndicator.js.map +2 -2
- package/dist/merge-fields/worldKnowledge.js.map +2 -2
- package/dist/mergeRelatorTermFields.js +9 -6
- package/dist/mergeRelatorTermFields.js.map +2 -2
- package/dist/normalize-dashes.js +7 -4
- package/dist/normalize-dashes.js.map +2 -2
- package/dist/normalize-identifiers.js.map +2 -2
- package/dist/normalize-utf8-diacritics.js.map +2 -2
- package/dist/normalizeFieldForComparison.js.map +1 -1
- package/dist/normalizeSubfieldValueForComparison.js.map +1 -1
- package/dist/punctuation2.js +5 -2
- package/dist/punctuation2.js.map +2 -2
- package/dist/reindexSubfield6OccurenceNumbers.js +11 -10
- package/dist/reindexSubfield6OccurenceNumbers.js.map +2 -2
- package/dist/removeDuplicateDataFields.js +3 -2
- package/dist/removeDuplicateDataFields.js.map +2 -2
- package/dist/removeInferiorDataFields.js.map +2 -2
- package/dist/resolveOrphanedSubfield6s.js +3 -2
- package/dist/resolveOrphanedSubfield6s.js.map +2 -2
- package/dist/sortSubfields.js +1 -1
- package/dist/sortSubfields.js.map +2 -2
- package/dist/stripPunctuation.js +4 -3
- package/dist/stripPunctuation.js.map +2 -2
- package/dist/subfield6Utils.js +4 -1
- package/dist/subfield6Utils.js.map +2 -2
- package/dist/subfield8Utils.js.map +2 -2
- package/dist/translate-terms.js +4 -3
- package/dist/translate-terms.js.map +2 -2
- package/dist/typeOfDate-008.js +3 -1
- package/dist/typeOfDate-008.js.map +2 -2
- package/dist/update-field-540.js.map +2 -2
- package/dist/urn.js +13 -12
- package/dist/urn.js.map +2 -2
- package/package.json +7 -7
- package/src/addMissingField041.js +8 -4
- package/src/addMissingField336.js +10 -5
- package/src/addMissingField337.js +9 -5
- package/src/addMissingField338.js +11 -6
- package/src/cyrillux-usemarcon-replacement.js +9 -5
- package/src/cyrillux.js +18 -12
- package/src/disambiguateSeriesStatements.js +4 -1
- package/src/drop-terms.js +8 -6
- package/src/fix-33X.js +10 -6
- package/src/fix-country-codes.js +7 -3
- package/src/fix-language-codes.js +8 -4
- package/src/fix-sami-041.js +13 -11
- package/src/indicator-fixes.js +10 -7
- package/src/merge-fields/counterpartField.js +10 -10
- package/src/merge-fields/mergableIndicator.js +3 -3
- package/src/merge-fields/worldKnowledge.js +11 -6
- package/src/mergeRelatorTermFields.js +12 -11
- package/src/normalize-dashes.js +11 -5
- package/src/normalize-identifiers.js +12 -19
- package/src/normalize-utf8-diacritics.js +6 -3
- package/src/normalizeFieldForComparison.js +2 -2
- package/src/normalizeSubfieldValueForComparison.js +2 -2
- package/src/punctuation2.js +34 -30
- package/src/reindexSubfield6OccurenceNumbers.js +13 -11
- package/src/removeDuplicateDataFields.js +29 -27
- package/src/removeInferiorDataFields.js +28 -24
- package/src/resolveOrphanedSubfield6s.js +6 -4
- package/src/sortSubfields.js +5 -5
- package/src/stripPunctuation.js +5 -3
- package/src/subfield6Utils.js +33 -35
- package/src/subfield8Utils.js +10 -7
- package/src/translate-terms.js +13 -9
- package/src/typeOfDate-008.js +4 -1
- package/src/update-field-540.js +7 -5
- package/src/urn.js +17 -13
- package/test-fixtures/drop-terms/02/metadata.json +1 -1
- package/test-fixtures/drop-terms/03/metadata.json +1 -1
- package/test-fixtures/drop-terms/04/metadata.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cyrillux-usemarcon-replacement.js"],
|
|
4
|
-
"sourcesContent": ["/*\n* cyrillux-usemarcon-replacement.js -- implement and improve https://github.com/NatLibFi/USEMARCON-Cyrillux/tree/master\n*\n* Author(s): Nicholas Volk <nicholas.volk@helsinki.fi>\n*\n*/\n\nimport clone from 'clone';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {default as fix33X} from './fix-33X.js';\nimport {default as add041} from './addMissingField041.js';\nimport {default as add336} from './addMissingField336.js';\nimport {default as add337} from './addMissingField337.js';\nimport {default as add338} from './addMissingField338.js';\nimport {default as fixCountryCodes} from './fix-country-codes.js';\nimport {default as fixLanguageCodes} from './fix-language-codes.js';\nimport {default as fixRelatorTerms} from './fixRelatorTerms.js';\nimport {default as fixIndicators} from './indicator-fixes.js';\nimport {default as fixPunctuation} from './punctuation2.js';\nimport {default as fixQualifyingInformation} from './normalize-qualifying-information.js';\nimport {sortAdjacentSubfields} from './sortSubfields.js';\n\n// import createDebugLogger from 'debug';\nimport {fieldHasSubfield, nvdebug, recordRemoveValuelessSubfields, recordToString, removeSubfield} from './utils.js';\n\n// const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/punctuation2');\n\nconst description = 'Replacement for Cyrillux usemarcon rules';\n\n// Extended original list with 541, 561, 562, 583, 584\n// 017, 044... et al are LL additions from 2019 (via USEMARCON-RDA)\nconst dropTags = ['001', '003', '010', '012', '014', '015', '016', '017', '019', '025', '029', '032', '035', '036', '037', '038', '042', '044', '049', '051', '061', '068', '071', '074', '079', '090', '091', '092', '094', '095', '096', '097', '099', '249', '261', '262', '350', '400', '411', '541', '561', '562', '574', '575', '577', '578', '583', '584', '589', '590', '591', '592', '593', '594', '595', '596', '597', '598', '599', '653', '698', '741', '742', '744', '751', '761', '790', '841', '842', '843', '844', '845', '850', '852', '853', '854', '855', '858', '859', '863', '864', '865', '866', '867', '868', '876', '877', '878', '882', '886', '887', '888', '890', '899'];\n\n\nexport default function () {\n return {\n description, fix, validate\n };\n\n function fix(record) {\n nvdebug(`${description}: fix`);\n realFix(record);\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n function realFixNonAleph(record) {\n if (isAlephRecord(record)) {\n return;\n }\n\n // Update LDR/17 to '4'\n record.leader = `${record.leader.substring(0, 17)}4${record.leader.substring(18, 24)}`;\n\n // Remove unwanted fields:\n record.fields = record.fields.filter(f => !dropTags.includes(f.tag));\n\n removeSubfield(record, '020', 'c');\n\n // Remove 084 fields that don't have $2 ykl (based on USEMARCON-RDA/bw_rda_kyril.rul code by LL 2019)\n record.fields = record.fields.filter(f => f.tag !== '084' || f.subfields.some(sf => sf.code === '2' && sf.value === 'ykl'));\n\n fieldSpecificStuff(record.fields);\n\n function fieldSpecificStuff(fields) {\n const [field, ...rest] = fields;\n\n if (field === undefined) {\n return;\n }\n\n removeOwnershipSubfield5(field);\n removeFromOldCatalog(field); // Remove LoC phrase \"[from old catalog]\" from srings\n translateFieldToFinnish(field);\n\n return fieldSpecificStuff(rest);\n }\n\n fixField040(record); // All $b values are changed to 'mul'. As a side effect 33X$b=>$a mappings are in Finnish! Ok in this domain!\n\n fieldSpecificStuff2(record.fields);\n\n function fieldSpecificStuff2(fields) {\n const [field, ...rest] = fields;\n\n if (field === undefined) {\n return;\n }\n\n removeSubfieldH(field); // NB! Do this only after 33X creation, as 245$h might be useful there!\n\n field100eKirjoittaja(field);\n\n function field100eKirjoittaja(f) { // LL 2019 USEMARCON-RDA rule\n if (f.tag === '100' && !fieldHasSubfield(f, 'e') && record.isBK()) {\n f.subfields = [{code: 'e', value: 'kirjoittaja.'}, ...f.subfields];\n sortAdjacentSubfields(f);\n // Punctuation will be done later on...\n return;\n }\n }\n\n field260To264s(field, record);\n\n // NB! 300 (before or after 33X creation?)\n field410To490And810(field, record);\n field440To490And830(field, record);\n // handle505(field); // not applying them usemarcon-cyrillux rules for field 505 as I can't understand their motivation.\n return fieldSpecificStuff2(rest);\n }\n\n }\n\n function realFixAll1(record) {\n fixLeader(record); // Fix defaults, esp. LDR/18=i\n\n fixCountryCodes().fix(record); // 008/15-17\n fixLanguageCodes().fix(record); // 008/35-37 AND 041 (note that all relevant subfield codes are fixed, not just $a)\n\n recordRemoveValuelessSubfields(record);\n\n // Field 028: use $b$a, not $a$b:\n const f028 = record.fields.filter(f => f.tag === '028');\n f028.forEach(f => sortAdjacentSubfields(f));\n\n add041().fix(record);\n\n }\n\n function realFixAll2(record) {\n fixQualifyingInformation().fix(record); // 015, 020, 024 and 028\n\n // Cyrillux specific code might change 040$b and thus affect these rules:\n fixRelatorTerms().fix(record);\n fix33X().fix(record); // 33X$a => 33X$a$b$2\n add336().fix(record);\n add337().fix(record);\n add338().fix(record);\n\n // The fixer below implements Cyrillux rules such as 245I1 | 245I1 | If (Exists(@100) Or Exists(@110) Or Exists(@111) Or Exists(@130)) Then '1' Else '0' and plenty of other good stuff:\n fixIndicators().fix(record);\n\n fixPunctuation().fix(record);\n }\n\n function realFix(record) {\n realFixAll1(record);\n\n realFixNonAleph(record);\n\n realFixAll2(record);\n\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n // Validation is currently done in subparts\n function validate(record) {\n nvdebug(`${description}: validate`);\n const originalString = recordToString(record);\n const clonedRecord = new MarcRecord(record, {subfieldValues: false});\n realFix(clonedRecord);\n const modifiedString = recordToString(clonedRecord);\n\n if (originalString === modifiedString) {\n return {message: [], valid: true};\n }\n\n return {message: ['Record changed'], valid: false}; // Less than descriptive but will do...\n\n }\n}\n\nfunction fixField040(record) {\n const f040 = record.get('040');\n\n const subfieldsBE = [\n {code: 'b', value: 'mul'},\n {code: 'e', value: 'rda'}\n ];\n\n // Add 040 if there isn't one:\n if (f040.length === 0) {\n const data = {tag: '040', ind1: ' ', ind2: ' ', subfields: subfieldsBE};\n\n record.insertField(data);\n return;\n }\n\n f040.forEach(f => fixField040Subfields(f));\n\n function fixField040Subfields(field) {\n field.subfields = field.subfields.filter(sf => !['b', 'e'].includes(sf.code));\n field.subfields.push(subfieldsBE[0]);\n field.subfields.push(subfieldsBE[1]);\n sortAdjacentSubfields(field); // put $b and $e to their proper places\n }\n\n}\n\nexport function removeFromOldCatalog(field) {\n if (!field.tag.match(/^(?:240|65[0135]|[1678](?:00|10|11|30))$/u)) {\n return;\n }\n // See https://catalog.loc.gov/vwebv/ui/en_US/htdocs/help/faqs.html for motivation\n field.subfields?.forEach(sf => removeFromOldCatalogFromSubfield(sf));\n\n function removeFromOldCatalogFromSubfield(subfield) {\n if (!subfield.value.includes('[from old catalog]')) {\n return;\n }\n subfield.value = subfield.value.replace(/ *\\[from old catalog\\]/gui, '');\n }\n}\n\nfunction removeSubfieldH(field) {\n if (!field.subfields || !['245', '246', '247', '740', '760', '762', '765', '767', '770', '772', '773', '774', '775', '776', '777', '780', '785', '786', '787', '788'].includes(field.tag)) {\n return;\n }\n\n const filteredFields = field.subfields.filter(sf => sf.code !== 'h');\n if (filteredFields.length > 0) {\n field.subfields = filteredFields;\n return;\n }\n\n}\n\nexport function removeOwnershipSubfield5(field) {\n if (!field.subfields || field.subfields.length === 0) {\n return;\n }\n const remainingSubfields = field.subfields.filter(sf => sf.code !== '5');\n if (remainingSubfields.length === 0) { // sanity check/robustness\n return;\n }\n field.subfields = remainingSubfields;\n}\n\nexport function fixLeader(record) {\n record.leader = `${record.leader.substring(0, 9)}a22${record.leader.substring(12, 18)}i${record.leader.substring(19, 20)}4500`;\n}\n\nfunction field410To490And810(field, record) { // might be generic... if so, move to utils...\n if (field.tag !== '410') {\n return;\n }\n\n const field810 = clone(field);\n\n field.tag = '490';\n field.ind1 = '1';\n field.ind2 = ' ';\n sortAdjacentSubfields(field);\n // 490: Fix punctuation elsewhere. (Note that the current support is lagging...)\n\n\n field810.tag = '810';\n field810.ind2 = ' ';\n // 810: Fix punctuation elsewhere. (Note that the current support is lagging...)\n record.insertField(field810);\n}\n\nfunction field440To490And830(field, record) { // might be generic... if so, move to utils...\n if (field.tag !== '440') {\n return;\n }\n\n const field830 = clone(field);\n\n field.tag = '490';\n field.ind1 = '1';\n field.ind2 = ' ';\n // 490: Fix punctuation elsewhere. (Note that the current support is lagging...)\n field830.tag = '830';\n // 830: Fix punctuation elsewhere. (Note that the current support is lagging...)\n record.insertField(field830);\n}\n\nfunction isAlephRecord(record) {\n // Records that are already in Aleph are not processed as aggressively as genuinely new ones:\n return record.fields.some(field => ['CAT', 'LKR', 'LOW', 'SID'].includes(field.tag));\n}\n\nfunction field260To264s(field, record) { // might be generic... if so, move to utils...\n // As per my quick reading of usemarcon-cyrillux\n if (field.tag !== '260') {\n return;\n }\n\n createCopyright264Field(field);\n\n field.tag = '264';\n field.ind1 = ' ';\n field.ind2 = '1';\n\n // NB! Usemarcon does not handle 260$e$f$g => 264$a$b$c, so I'm not botherin with it either... (However, we could check our merge reducer code...)\n\n function getCopyrightYear(string) {\n if (string.match(/^(?:\\[?[Ccp]|[^0-9]*(?:cop|\u00A9|\u2117))[^0-9]*(?:1[789][0-9][0-9]|20[0-2][0-9])[^0-9]*$/u)) {\n return string.replace(/[^0-9]/ug, '');\n }\n return false;\n }\n\n field.subfields?.forEach(sf => field260To264Normalization(sf));\n\n function field260To264Normalization(subfield) {\n subfield.value = field260To264Normalization2(subfield);\n }\n\n function createCopyright264Value(field) {\n // Extract/split copyright year to a separate field:\n const [c] = field.subfields.filter(sf => sf.code === 'c');\n if (!c) {\n return undefined;\n }\n const copyrightYear = getCopyrightYear(c.value);\n if (!copyrightYear) {\n return undefined;\n }\n const copType = c.value.match(/(?:^\\[?p|\u2117)/u) ? '\u2117' : '\u00A9';\n const returnValue = c.value.includes('[') ? `[${copType}${copyrightYear}]` : `${copType}${copyrightYear}`;\n // Moidy the original value:\n c.value = `[${copyrightYear}]`;\n return returnValue;\n }\n\n function createCopyright264Field(field) {\n const c = createCopyright264Value(field);\n if (!c) {\n return undefined;\n }\n const data = {'tag': '264', 'ind1': ' ', 'ind2': '4', 'subfields': [{'code': 'c', 'value': c}]};\n record.insertField(data);\n }\n\n function field260To264Normalization2(subfield) {\n if (subfield.code === 'a') {\n return subfield.value.replace(/\\b[Ss]\\. ?l\\./u, 'Kustannuspaikka tuntematon');\n }\n if (subfield.code === 'b') {\n return subfield.value.replace(/\\b[Ss]\\. ?n\\./u, 'kustantaja tuntematon');\n }\n if (subfield.code === 'c') {\n const year = getCopyrightYear(subfield.value);\n if (year) {\n const c = subfield.value.match(/(?:^p|\u2117)/u) ? 'p' : 'c';\n if (subfield.value.includes('[')) {\n return `${c}[${year}]`;\n }\n return `${c}${year}`;\n }\n return subfield.value.replace(/\\b[Ss]\\. ?a\\./u, 'julkaisuaika tuntematon');\n }\n return subfield.value;\n }\n\n\n}\n\n/*\nfunction handle505(field) {\n if (field.tag !== '505') {\n return;\n }\n // Don't know how/why usemarcon-cyrillux is so sure about ind1...\n field.ind1 = '0';\n // usemarcon-cyrillux drops irrelevant subfields, so we do the same. However, we have included some control subfields in the kept side:\n const keptSubfields = field.subfields.filter(sf => ['a', 'g', 'r', 't', 'u', '6', '8', '9'].includes(sf.code));\n\n if (keptSubfields.some(sf => ['a', 'g', 'r', 't', 'u'].includes(sf.code))) {\n field.subfields = keptSubfields;\n return;\n }\n}\n*/\n\nfunction translateFieldToFinnish(field) {\n if (!['020', '300'].includes(field.tag)) {\n return;\n }\n field.subfields?.forEach(sf => translateSubfieldToFinnish(sf));\n\n function translateSubfieldToFinnish(subfield) {\n if (field.tag === '020' && ['a', 'q', 'z'].includes(subfield.code)) {\n subfield.value = finnishTranslationsAndMappings(expandFinnishAbbreviations(expandSwedishAbbreviations(expandEnglishAbbreviations(subfield.value))));\n return;\n }\n if (field.tag === '300') {\n subfield.value = finnishTranslationsAndMappings(expandFinnishAbbreviations(expandSwedishAbbreviations(expandEnglishAbbreviations(subfield.value))));\n return;\n }\n }\n}\n\nfunction expandEnglishAbbreviations(value) {\n return value.replace(/\\bbk\\.\\b/gui, 'book').\n replace(/chiefly col\\./ui, 'chiefly color').\n replace(/col\\. ill\\./ui, 'color illustrations').\n replace(/diagrs\\./ui, 'diagrams').\n replace(/\\bhbk\\.\\b/gui, 'hardcover').replace(/\\bhbk\\b/gui, 'hardcover'). // expand to MTS-compliant form\n replace(/\\b1 hr\\./gui, '1 hour').\n replace(/\\bhr\\./gui, 'hours').\n replace(/\\bill\\./gui, 'illustrated'). // or illustrations (or Swedish \"illustrerad\" or...)\n replace(/\\billus\\./gui, 'illustrated'). // or illustrations\n replace(/incl\\./gui, 'includes').\n replace(/fold\\.? maps/gui, 'folded maps').\n // replace(/\\bmin\\./gu, 'minutes').\n // replace(/\\bmin\\b/gu, 'minutes').\n replace(/\\bp\\.\\b/gui, 'pages').replace(/\\bp\\b/gu, 'pages').\n replace(/\\bpbk\\.\\b/gui, 'paperback').replace(/\\bpbk\\b/gui, 'paperback'). // expand to MTS-compliant form\n replace(/\\bpdf\\b/gui, 'PDF').\n replace(/\\bports\\./gui, 'portraits').\n replace('sd., col.', 'sound, color').\n replace(/ *\\((?:chiefly col\\.|chiefly color|some col[s.])\\)/gui, '').\n replace(/\\b1 hr\\./gui, '1 hour');\n}\n\nfunction expandFinnishAbbreviations(value) {\n return value.replace(/\\bcn\\. /gu, 'noin ').\n // replace(/\\bmin\\./gu, 'minuuttia').\n // replace(/\\bmin\\b/gu, 'minuuttia').\n replace(/\\bnid\\./gu, 'nidottu').replace(/\\bnid\\b/gui, 'nidottu').\n replace(/\\bsid\\./gu, 'sidottu').replace(/\\bsid\\b/gui, 'sidottu').\n replace(/\\bverkkojulk\\.\\b/gu, 'verkkojulkaisu').replace(/\\bverkkojulk\\b/gu, 'verkkojulkaisu').\n replace(/^\\(([^)]+)\\)$/u, '$1');\n // <- removal of brackets above could use a better location\n}\n\nfunction expandSwedishAbbreviations(value) {\n return value.replace(/\\bca\\. /gu, 'circa ').\n replace(/\\bhft\\./gui, 'h\u00E4ftad').replace(/\\bhft\\b/gui, 'h\u00E4ftad');\n // replace(/\\bmin\\./gu, 'minuter').\n // replace(/\\bmin\\b/gu, 'minuter');\n}\n\nfunction finnishTranslationsAndMappings(value) {\n return value.replace('analog', 'analoginen').\n replace('approximately', 'noin').\n replace('audio discs', '\u00E4\u00E4nilevy\u00E4').\n replace('black and white', 'mustavalkoinen').\n replace(/\\bbilaga\\b/gui, 'liite').\n replace(/\\bbilagor\\b/gui, 'liitett\u00E4').\n // https://github.com/NatLibFi/USEMARCON-BOOKWHERE-RDA/blob/master/bw_rda_kyril.rul#L365\n replace(/(\\b1\\]?) \u0441\\./gui, '$1 sivu').\n replace(/(\\d\\]?) \u0441\\./gui, '$1 sivua').\n replace(/(\\d) \u0441\u043C/gui, '$1 cm').\n\n replace(/\\bcharts\\b/gui, 'kaavioita').\n replace('chiefly color illustrations', 'p\u00E4\u00E4osin v\u00E4rikuvitettu').\n replace('chiefly', 'p\u00E4\u00E4osin').\n replace(/\\bcirca\\b/gui, 'noin').\n replace(/coil[- ]?bound/gui, 'kierreselk\u00E4').\n replace('color illustrations', 'v\u00E4rikuvitus').\n replace(/comb[- ]?bound/gui, 'kierreselk\u00E4').\n replace(/\\bdigital\\b/gui, 'digitaalinen').\n replace(/\\belectronic book\\b/gui, 'verkkoaineisto').\n replace('(flera nummersviter)', '(useita numerointijaksoja)').\n replace(/\\bfolded sheet\\b/gui, 'taitelehti').\n replace(/\\bf\u00E4rgillustratione[nr]\\b/gui, 'v\u00E4rikuvitus').\n replace(/\\bhard(?:back|cover)\\b/gui, 'kovakantinen').\n replace(/\\bhours\\b/gui, 'tuntia').\n replace(/\\bi flera nummersviter/gui, 'useina numerointijaksoina').\n replace('illustrated', 'kuvitettu').\n replace(/illustrations?\\b/gui, 'kuvitettu'). // Based on usemacron-bookwhere (NB! usemarcon-cyrillux had kuvitus/kuvitettu)\n replace(/\\binbunden\\b/gui, 'kovakantinen'). // swe\n replace(/\\binsert\\b/gui, 'liite').\n replace(/\\binserts\\b/gui, 'liitteit\u00E4').\n replace(/\\bin various pagings/gui, 'useina numerointijaksoina').\n replace('leaves of plates', 'kuvalehte\u00E4').\n replace(/\\bljudskiva\\b/gui, '\u00E4\u00E4nilevy').\n replace(/\\bljudskivor\\b/gui, '\u00E4\u00E4nilevy\u00E4').\n replace(/\\bmap\\b/gui, 'kartta').\n replace(/\\bmaps\\b/gui, 'karttoja'). // or karttaa?\n replace('minutes', 'minuuttia').\n replace('mjuka p\u00E4rmar', 'pehme\u00E4kantinen').\n replace('online resource', 'verkkoaineisto').\n replace('onlineresurs', 'verkkoaineisto').\n replace('onumrerade', 'numeroimatonta').\n replace('pages of plates', 'kuvalehte\u00E4').\n replace(/\\bpages\\b/gui, 'sivua').\n replace(/\\bpaperback\\b/gui, 'pehme\u00E4kantinen'). // MTS alt\n replace(/\\bSeiten\\b/gu, 'sivua').\n replace(/\\bsoftcover\\b/gui, 'pehme\u00E4kantinen'). // MTS pref\n replace('sound, color', '\u00E4\u00E4nellinen, v\u00E4rillinen').\n replace('sound cassettes', '\u00E4\u00E4nikasettia').replace('sound cassette', '\u00E4\u00E4nikasetti').\n replace('sound discs', '\u00E4\u00E4nilevy\u00E4').replace(/sound disc\\b/gui, '\u00E4\u00E4nilevy').\n replace(/(?:spiral[- ]?bound|spiralrygg)/gui, 'kierreselk\u00E4').\n replace('svartvit', 'mustavalkoinen').\n replace('unnumbered', 'numeroimatonta').\n replace('(various pagings)', '(useita numerointijaksoja)').\n replace(/\\bverkkojulkaisu\\b/gui, 'verkkoaineisto').\n replace('videodiscs', 'videolevy\u00E4').\n replace('videodisc', 'videolevy').\n replace(/\\b1 hour\\b/gui, '1 tunti');\n\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/* eslint-disable max-lines */\n\n/*\n* cyrillux-usemarcon-replacement.js -- implement and improve https://github.com/NatLibFi/USEMARCON-Cyrillux/tree/master\n*\n* Author(s): Nicholas Volk <nicholas.volk@helsinki.fi>\n*\n*/\n\nimport clone from 'clone';\nimport createDebugLogger from 'debug';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {default as fix33X} from './fix-33X.js';\nimport {default as add041} from './addMissingField041.js';\nimport {default as add336} from './addMissingField336.js';\nimport {default as add337} from './addMissingField337.js';\nimport {default as add338} from './addMissingField338.js';\nimport {default as fixCountryCodes} from './fix-country-codes.js';\nimport {default as fixLanguageCodes} from './fix-language-codes.js';\nimport {default as fixRelatorTerms} from './fixRelatorTerms.js';\nimport {default as fixIndicators} from './indicator-fixes.js';\nimport {default as fixPunctuation} from './punctuation2.js';\nimport {default as fixQualifyingInformation} from './normalize-qualifying-information.js';\nimport {sortAdjacentSubfields} from './sortSubfields.js';\nimport {fieldHasSubfield, nvdebug, recordRemoveValuelessSubfields, recordToString, removeSubfield} from './utils.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/cyrillux-usermarcon-replacement');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst description = 'Replacement for Cyrillux usemarcon rules';\n\n// Extended original list with 541, 561, 562, 583, 584\n// 017, 044... et al are LL additions from 2019 (via USEMARCON-RDA)\nconst dropTags = ['001', '003', '010', '012', '014', '015', '016', '017', '019', '025', '029', '032', '035', '036', '037', '038', '042', '044', '049', '051', '061', '068', '071', '074', '079', '090', '091', '092', '094', '095', '096', '097', '099', '249', '261', '262', '350', '400', '411', '541', '561', '562', '574', '575', '577', '578', '583', '584', '589', '590', '591', '592', '593', '594', '595', '596', '597', '598', '599', '653', '698', '741', '742', '744', '751', '761', '790', '841', '842', '843', '844', '845', '850', '852', '853', '854', '855', '858', '859', '863', '864', '865', '866', '867', '868', '876', '877', '878', '882', '886', '887', '888', '890', '899'];\n\n\n// eslint-disable-next-line max-lines-per-function\nexport default function () {\n return {\n description, fix, validate\n };\n\n function fix(record) {\n nvdebug(`${description}: fix`, debugDev);\n realFix(record);\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n function realFixNonAleph(record) {\n if (isAlephRecord(record)) {\n return;\n }\n\n // Update LDR/17 to '4'\n record.leader = `${record.leader.substring(0, 17)}4${record.leader.substring(18, 24)}`;\n\n // Remove unwanted fields:\n record.fields = record.fields.filter(f => !dropTags.includes(f.tag));\n\n removeSubfield(record, '020', 'c');\n\n // Remove 084 fields that don't have $2 ykl (based on USEMARCON-RDA/bw_rda_kyril.rul code by LL 2019)\n record.fields = record.fields.filter(f => f.tag !== '084' || f.subfields.some(sf => sf.code === '2' && sf.value === 'ykl'));\n\n fieldSpecificStuff(record.fields);\n\n function fieldSpecificStuff(fields) {\n const [field, ...rest] = fields;\n\n if (field === undefined) {\n return;\n }\n\n removeOwnershipSubfield5(field);\n removeFromOldCatalog(field); // Remove LoC phrase \"[from old catalog]\" from srings\n translateFieldToFinnish(field);\n\n return fieldSpecificStuff(rest);\n }\n\n fixField040(record); // All $b values are changed to 'mul'. As a side effect 33X$b=>$a mappings are in Finnish! Ok in this domain!\n\n fieldSpecificStuff2(record.fields);\n\n function fieldSpecificStuff2(fields) {\n const [field, ...rest] = fields;\n\n if (field === undefined) {\n return;\n }\n\n removeSubfieldH(field); // NB! Do this only after 33X creation, as 245$h might be useful there!\n\n field100eKirjoittaja(field);\n\n function field100eKirjoittaja(f) { // LL 2019 USEMARCON-RDA rule\n if (f.tag === '100' && !fieldHasSubfield(f, 'e') && record.isBK()) {\n f.subfields = [{code: 'e', value: 'kirjoittaja.'}, ...f.subfields];\n sortAdjacentSubfields(f);\n // Punctuation will be done later on...\n return;\n }\n }\n\n field260To264s(field, record);\n\n // NB! 300 (before or after 33X creation?)\n field410To490And810(field, record);\n field440To490And830(field, record);\n // handle505(field); // not applying them usemarcon-cyrillux rules for field 505 as I can't understand their motivation.\n return fieldSpecificStuff2(rest);\n }\n\n }\n\n function realFixAll1(record) {\n fixLeader(record); // Fix defaults, esp. LDR/18=i\n\n fixCountryCodes().fix(record); // 008/15-17\n fixLanguageCodes().fix(record); // 008/35-37 AND 041 (note that all relevant subfield codes are fixed, not just $a)\n\n recordRemoveValuelessSubfields(record);\n\n // Field 028: use $b$a, not $a$b:\n const f028 = record.fields.filter(f => f.tag === '028');\n f028.forEach(f => sortAdjacentSubfields(f));\n\n add041().fix(record);\n\n }\n\n function realFixAll2(record) {\n fixQualifyingInformation().fix(record); // 015, 020, 024 and 028\n\n // Cyrillux specific code might change 040$b and thus affect these rules:\n fixRelatorTerms().fix(record);\n fix33X().fix(record); // 33X$a => 33X$a$b$2\n add336().fix(record);\n add337().fix(record);\n add338().fix(record);\n\n // The fixer below implements Cyrillux rules such as 245I1 | 245I1 | If (Exists(@100) Or Exists(@110) Or Exists(@111) Or Exists(@130)) Then '1' Else '0' and plenty of other good stuff:\n fixIndicators().fix(record);\n\n fixPunctuation().fix(record);\n }\n\n function realFix(record) {\n realFixAll1(record);\n\n realFixNonAleph(record);\n\n realFixAll2(record);\n\n const res = {message: [], fix: [], valid: true};\n return res;\n }\n\n // Validation is currently done in subparts\n function validate(record) {\n nvdebug(`${description}: validate`, debugDev);\n const originalString = recordToString(record);\n const clonedRecord = new MarcRecord(record, {subfieldValues: false});\n realFix(clonedRecord);\n const modifiedString = recordToString(clonedRecord);\n\n if (originalString === modifiedString) {\n return {message: [], valid: true};\n }\n\n return {message: ['Record changed'], valid: false}; // Less than descriptive but will do...\n\n }\n}\n\nfunction fixField040(record) {\n const f040 = record.get('040');\n\n const subfieldsBE = [\n {code: 'b', value: 'mul'},\n {code: 'e', value: 'rda'}\n ];\n\n // Add 040 if there isn't one:\n if (f040.length === 0) {\n const data = {tag: '040', ind1: ' ', ind2: ' ', subfields: subfieldsBE};\n\n record.insertField(data);\n return;\n }\n\n f040.forEach(f => fixField040Subfields(f));\n\n function fixField040Subfields(field) {\n field.subfields = field.subfields.filter(sf => !['b', 'e'].includes(sf.code));\n field.subfields.push(subfieldsBE[0]);\n field.subfields.push(subfieldsBE[1]);\n sortAdjacentSubfields(field); // put $b and $e to their proper places\n }\n\n}\n\nexport function removeFromOldCatalog(field) {\n if (!field.tag.match(/^(?:240|65[0135]|[1678](?:00|10|11|30))$/u)) {\n return;\n }\n // See https://catalog.loc.gov/vwebv/ui/en_US/htdocs/help/faqs.html for motivation\n field.subfields?.forEach(sf => removeFromOldCatalogFromSubfield(sf));\n\n function removeFromOldCatalogFromSubfield(subfield) {\n if (!subfield.value.includes('[from old catalog]')) {\n return;\n }\n subfield.value = subfield.value.replace(/ *\\[from old catalog\\]/gui, '');\n }\n}\n\nfunction removeSubfieldH(field) {\n if (!field.subfields || !['245', '246', '247', '740', '760', '762', '765', '767', '770', '772', '773', '774', '775', '776', '777', '780', '785', '786', '787', '788'].includes(field.tag)) {\n return;\n }\n\n const filteredFields = field.subfields.filter(sf => sf.code !== 'h');\n if (filteredFields.length > 0) {\n field.subfields = filteredFields;\n return;\n }\n\n}\n\nexport function removeOwnershipSubfield5(field) {\n if (!field.subfields || field.subfields.length === 0) {\n return;\n }\n const remainingSubfields = field.subfields.filter(sf => sf.code !== '5');\n if (remainingSubfields.length === 0) { // sanity check/robustness\n return;\n }\n field.subfields = remainingSubfields;\n}\n\nexport function fixLeader(record) {\n record.leader = `${record.leader.substring(0, 9)}a22${record.leader.substring(12, 18)}i${record.leader.substring(19, 20)}4500`;\n}\n\nfunction field410To490And810(field, record) { // might be generic... if so, move to utils...\n if (field.tag !== '410') {\n return;\n }\n\n const field810 = clone(field);\n\n field.tag = '490';\n field.ind1 = '1';\n field.ind2 = ' ';\n sortAdjacentSubfields(field);\n // 490: Fix punctuation elsewhere. (Note that the current support is lagging...)\n\n\n field810.tag = '810';\n field810.ind2 = ' ';\n // 810: Fix punctuation elsewhere. (Note that the current support is lagging...)\n record.insertField(field810);\n}\n\nfunction field440To490And830(field, record) { // might be generic... if so, move to utils...\n if (field.tag !== '440') {\n return;\n }\n\n const field830 = clone(field);\n\n field.tag = '490';\n field.ind1 = '1';\n field.ind2 = ' ';\n // 490: Fix punctuation elsewhere. (Note that the current support is lagging...)\n field830.tag = '830';\n // 830: Fix punctuation elsewhere. (Note that the current support is lagging...)\n record.insertField(field830);\n}\n\nfunction isAlephRecord(record) {\n // Records that are already in Aleph are not processed as aggressively as genuinely new ones:\n return record.fields.some(field => ['CAT', 'LKR', 'LOW', 'SID'].includes(field.tag));\n}\n\nfunction field260To264s(field, record) { // might be generic... if so, move to utils...\n // As per my quick reading of usemarcon-cyrillux\n if (field.tag !== '260') {\n return;\n }\n\n createCopyright264Field(field);\n\n field.tag = '264';\n field.ind1 = ' ';\n field.ind2 = '1';\n\n // NB! Usemarcon does not handle 260$e$f$g => 264$a$b$c, so I'm not botherin with it either... (However, we could check our merge reducer code...)\n\n function getCopyrightYear(string) {\n if (string.match(/^(?:\\[?[Ccp]|[^0-9]*(?:cop|\u00A9|\u2117))[^0-9]*(?:1[789][0-9][0-9]|20[0-2][0-9])[^0-9]*$/u)) {\n return string.replace(/[^0-9]/ug, '');\n }\n return false;\n }\n\n field.subfields?.forEach(sf => field260To264Normalization(sf));\n\n function field260To264Normalization(subfield) {\n subfield.value = field260To264Normalization2(subfield);\n }\n\n function createCopyright264Value(field) {\n // Extract/split copyright year to a separate field:\n const [c] = field.subfields.filter(sf => sf.code === 'c');\n if (!c) {\n return undefined;\n }\n const copyrightYear = getCopyrightYear(c.value);\n if (!copyrightYear) {\n return undefined;\n }\n const copType = c.value.match(/(?:^\\[?p|\u2117)/u) ? '\u2117' : '\u00A9';\n const returnValue = c.value.includes('[') ? `[${copType}${copyrightYear}]` : `${copType}${copyrightYear}`;\n // Moidy the original value:\n c.value = `[${copyrightYear}]`;\n return returnValue;\n }\n\n function createCopyright264Field(field) {\n const c = createCopyright264Value(field);\n if (!c) {\n return undefined;\n }\n const data = {'tag': '264', 'ind1': ' ', 'ind2': '4', 'subfields': [{'code': 'c', 'value': c}]};\n record.insertField(data);\n }\n\n function field260To264Normalization2(subfield) {\n if (subfield.code === 'a') {\n return subfield.value.replace(/\\b[Ss]\\. ?l\\./u, 'Kustannuspaikka tuntematon');\n }\n if (subfield.code === 'b') {\n return subfield.value.replace(/\\b[Ss]\\. ?n\\./u, 'kustantaja tuntematon');\n }\n if (subfield.code === 'c') {\n const year = getCopyrightYear(subfield.value);\n if (year) {\n const c = subfield.value.match(/(?:^p|\u2117)/u) ? 'p' : 'c';\n if (subfield.value.includes('[')) {\n return `${c}[${year}]`;\n }\n return `${c}${year}`;\n }\n return subfield.value.replace(/\\b[Ss]\\. ?a\\./u, 'julkaisuaika tuntematon');\n }\n return subfield.value;\n }\n\n\n}\n\n/*\nfunction handle505(field) {\n if (field.tag !== '505') {\n return;\n }\n // Don't know how/why usemarcon-cyrillux is so sure about ind1...\n field.ind1 = '0';\n // usemarcon-cyrillux drops irrelevant subfields, so we do the same. However, we have included some control subfields in the kept side:\n const keptSubfields = field.subfields.filter(sf => ['a', 'g', 'r', 't', 'u', '6', '8', '9'].includes(sf.code));\n\n if (keptSubfields.some(sf => ['a', 'g', 'r', 't', 'u'].includes(sf.code))) {\n field.subfields = keptSubfields;\n return;\n }\n}\n*/\n\nfunction translateFieldToFinnish(field) {\n if (!['020', '300'].includes(field.tag)) {\n return;\n }\n field.subfields?.forEach(sf => translateSubfieldToFinnish(sf));\n\n function translateSubfieldToFinnish(subfield) {\n if (field.tag === '020' && ['a', 'q', 'z'].includes(subfield.code)) {\n subfield.value = finnishTranslationsAndMappings(expandFinnishAbbreviations(expandSwedishAbbreviations(expandEnglishAbbreviations(subfield.value))));\n return;\n }\n if (field.tag === '300') {\n subfield.value = finnishTranslationsAndMappings(expandFinnishAbbreviations(expandSwedishAbbreviations(expandEnglishAbbreviations(subfield.value))));\n return;\n }\n }\n}\n\nfunction expandEnglishAbbreviations(value) {\n return value.replace(/\\bbk\\.\\b/gui, 'book').\n replace(/chiefly col\\./ui, 'chiefly color').\n replace(/col\\. ill\\./ui, 'color illustrations').\n replace(/diagrs\\./ui, 'diagrams').\n replace(/\\bhbk\\.\\b/gui, 'hardcover').replace(/\\bhbk\\b/gui, 'hardcover'). // expand to MTS-compliant form\n replace(/\\b1 hr\\./gui, '1 hour').\n replace(/\\bhr\\./gui, 'hours').\n replace(/\\bill\\./gui, 'illustrated'). // or illustrations (or Swedish \"illustrerad\" or...)\n replace(/\\billus\\./gui, 'illustrated'). // or illustrations\n replace(/incl\\./gui, 'includes').\n replace(/fold\\.? maps/gui, 'folded maps').\n // replace(/\\bmin\\./gu, 'minutes').\n // replace(/\\bmin\\b/gu, 'minutes').\n replace(/\\bp\\.\\b/gui, 'pages').replace(/\\bp\\b/gu, 'pages').\n replace(/\\bpbk\\.\\b/gui, 'paperback').replace(/\\bpbk\\b/gui, 'paperback'). // expand to MTS-compliant form\n replace(/\\bpdf\\b/gui, 'PDF').\n replace(/\\bports\\./gui, 'portraits').\n replace('sd., col.', 'sound, color').\n replace(/ *\\((?:chiefly col\\.|chiefly color|some col[s.])\\)/gui, '').\n replace(/\\b1 hr\\./gui, '1 hour');\n}\n\nfunction expandFinnishAbbreviations(value) {\n return value.replace(/\\bcn\\. /gu, 'noin ').\n // replace(/\\bmin\\./gu, 'minuuttia').\n // replace(/\\bmin\\b/gu, 'minuuttia').\n replace(/\\bnid\\./gu, 'nidottu').replace(/\\bnid\\b/gui, 'nidottu').\n replace(/\\bsid\\./gu, 'sidottu').replace(/\\bsid\\b/gui, 'sidottu').\n replace(/\\bverkkojulk\\.\\b/gu, 'verkkojulkaisu').replace(/\\bverkkojulk\\b/gu, 'verkkojulkaisu').\n replace(/^\\(([^)]+)\\)$/u, '$1');\n // <- removal of brackets above could use a better location\n}\n\nfunction expandSwedishAbbreviations(value) {\n return value.replace(/\\bca\\. /gu, 'circa ').\n replace(/\\bhft\\./gui, 'h\u00E4ftad').replace(/\\bhft\\b/gui, 'h\u00E4ftad');\n // replace(/\\bmin\\./gu, 'minuter').\n // replace(/\\bmin\\b/gu, 'minuter');\n}\n\nfunction finnishTranslationsAndMappings(value) {\n return value.replace('analog', 'analoginen').\n replace('approximately', 'noin').\n replace('audio discs', '\u00E4\u00E4nilevy\u00E4').\n replace('black and white', 'mustavalkoinen').\n replace(/\\bbilaga\\b/gui, 'liite').\n replace(/\\bbilagor\\b/gui, 'liitett\u00E4').\n // https://github.com/NatLibFi/USEMARCON-BOOKWHERE-RDA/blob/master/bw_rda_kyril.rul#L365\n replace(/(\\b1\\]?) \u0441\\./gui, '$1 sivu').\n replace(/(\\d\\]?) \u0441\\./gui, '$1 sivua').\n replace(/(\\d) \u0441\u043C/gui, '$1 cm').\n\n replace(/\\bcharts\\b/gui, 'kaavioita').\n replace('chiefly color illustrations', 'p\u00E4\u00E4osin v\u00E4rikuvitettu').\n replace('chiefly', 'p\u00E4\u00E4osin').\n replace(/\\bcirca\\b/gui, 'noin').\n replace(/coil[- ]?bound/gui, 'kierreselk\u00E4').\n replace('color illustrations', 'v\u00E4rikuvitus').\n replace(/comb[- ]?bound/gui, 'kierreselk\u00E4').\n replace(/\\bdigital\\b/gui, 'digitaalinen').\n replace(/\\belectronic book\\b/gui, 'verkkoaineisto').\n replace('(flera nummersviter)', '(useita numerointijaksoja)').\n replace(/\\bfolded sheet\\b/gui, 'taitelehti').\n replace(/\\bf\u00E4rgillustratione[nr]\\b/gui, 'v\u00E4rikuvitus').\n replace(/\\bhard(?:back|cover)\\b/gui, 'kovakantinen').\n replace(/\\bhours\\b/gui, 'tuntia').\n replace(/\\bi flera nummersviter/gui, 'useina numerointijaksoina').\n replace('illustrated', 'kuvitettu').\n replace(/illustrations?\\b/gui, 'kuvitettu'). // Based on usemacron-bookwhere (NB! usemarcon-cyrillux had kuvitus/kuvitettu)\n replace(/\\binbunden\\b/gui, 'kovakantinen'). // swe\n replace(/\\binsert\\b/gui, 'liite').\n replace(/\\binserts\\b/gui, 'liitteit\u00E4').\n replace(/\\bin various pagings/gui, 'useina numerointijaksoina').\n replace('leaves of plates', 'kuvalehte\u00E4').\n replace(/\\bljudskiva\\b/gui, '\u00E4\u00E4nilevy').\n replace(/\\bljudskivor\\b/gui, '\u00E4\u00E4nilevy\u00E4').\n replace(/\\bmap\\b/gui, 'kartta').\n replace(/\\bmaps\\b/gui, 'karttoja'). // or karttaa?\n replace('minutes', 'minuuttia').\n replace('mjuka p\u00E4rmar', 'pehme\u00E4kantinen').\n replace('online resource', 'verkkoaineisto').\n replace('onlineresurs', 'verkkoaineisto').\n replace('onumrerade', 'numeroimatonta').\n replace('pages of plates', 'kuvalehte\u00E4').\n replace(/\\bpages\\b/gui, 'sivua').\n replace(/\\bpaperback\\b/gui, 'pehme\u00E4kantinen'). // MTS alt\n replace(/\\bSeiten\\b/gu, 'sivua').\n replace(/\\bsoftcover\\b/gui, 'pehme\u00E4kantinen'). // MTS pref\n replace('sound, color', '\u00E4\u00E4nellinen, v\u00E4rillinen').\n replace('sound cassettes', '\u00E4\u00E4nikasettia').replace('sound cassette', '\u00E4\u00E4nikasetti').\n replace('sound discs', '\u00E4\u00E4nilevy\u00E4').replace(/sound disc\\b/gui, '\u00E4\u00E4nilevy').\n replace(/(?:spiral[- ]?bound|spiralrygg)/gui, 'kierreselk\u00E4').\n replace('svartvit', 'mustavalkoinen').\n replace('unnumbered', 'numeroimatonta').\n replace('(various pagings)', '(useita numerointijaksoja)').\n replace(/\\bverkkojulkaisu\\b/gui, 'verkkoaineisto').\n replace('videodiscs', 'videolevy\u00E4').\n replace('videodisc', 'videolevy').\n replace(/\\b1 hour\\b/gui, '1 tunti');\n\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["field"]
|
|
7
7
|
}
|
package/dist/cyrillux.js
CHANGED
|
@@ -8,6 +8,9 @@ import { default as sortFields } from "./sortFields.js";
|
|
|
8
8
|
import { default as reindexSubfield6OccurenceNumbers } from "./reindexSubfield6OccurenceNumbers.js";
|
|
9
9
|
import { fieldStripPunctuation } from "./punctuation2.js";
|
|
10
10
|
import { getLanguageCode } from "./addMissingField041.js";
|
|
11
|
+
import createDebugLogger from "debug";
|
|
12
|
+
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda/cyrillux");
|
|
13
|
+
const debugDev = debug.extend("dev");
|
|
11
14
|
const iso9Trans = "ISO9 <TRANS>";
|
|
12
15
|
const cyrillicTrans = "CYRILLIC <TRANS>";
|
|
13
16
|
const sfs4900Trans = "SFS4900 <TRANS>";
|
|
@@ -127,9 +130,9 @@ export default function(config = {}) {
|
|
|
127
130
|
return { code: subfield.code, value: subfield.value };
|
|
128
131
|
}
|
|
129
132
|
const conversionResult = sfs4900.convertToLatin(subfield.value, inputLang);
|
|
130
|
-
|
|
133
|
+
nvdebug(`${JSON.stringify(conversionResult)}`, debugDev);
|
|
131
134
|
const result = conversionResult.result;
|
|
132
|
-
|
|
135
|
+
nvdebug(`${JSON.stringify(result)}`, debugDev);
|
|
133
136
|
return { code: subfield.code, value: result };
|
|
134
137
|
}
|
|
135
138
|
function mapField(field, occurrenceNumber, iso92 = true, lang = "rus") {
|
|
@@ -185,7 +188,7 @@ export default function(config = {}) {
|
|
|
185
188
|
if (!config.retainCyrillic) {
|
|
186
189
|
return void 0;
|
|
187
190
|
}
|
|
188
|
-
nvdebug(`Derive CYR 880 from ${fieldToString(field)}
|
|
191
|
+
nvdebug(`Derive CYR 880 from ${fieldToString(field)}`, debugDev);
|
|
189
192
|
const newSubfield6 = deriveSubfield6(field.tag, field.subfields, occurrenceNumber);
|
|
190
193
|
const newSubfield9 = fieldHasSubfield(field, "9", cyrillicTrans) ? [] : [{ code: "9", value: cyrillicTrans }];
|
|
191
194
|
const subfields = [
|
|
@@ -194,7 +197,7 @@ export default function(config = {}) {
|
|
|
194
197
|
...newSubfield9
|
|
195
198
|
];
|
|
196
199
|
const newField = { tag: "880", ind1: field.ind1, ind2: field.ind2, subfields };
|
|
197
|
-
nvdebug(` New CYR 880 ${fieldToString(newField)}
|
|
200
|
+
nvdebug(` New CYR 880 ${fieldToString(newField)}`, debugDev);
|
|
198
201
|
return newField;
|
|
199
202
|
}
|
|
200
203
|
function getNewOccurrenceNumber(originalField, record, maxCreatedOccurrenceNumber = 0) {
|
|
@@ -231,8 +234,8 @@ export default function(config = {}) {
|
|
|
231
234
|
return false;
|
|
232
235
|
}
|
|
233
236
|
const [pairedField] = existingPairedFields;
|
|
234
|
-
nvdebug(`LOOKING FOR SFS4900 PAIR: ${fieldToString(field)}
|
|
235
|
-
nvdebug(` HAVING PAIRED FIELD: ${fieldToString(pairedField)}
|
|
237
|
+
nvdebug(`LOOKING FOR SFS4900 PAIR: ${fieldToString(field)}`, debugDev);
|
|
238
|
+
nvdebug(` HAVING PAIRED FIELD: ${fieldToString(pairedField)}`, debugDev);
|
|
236
239
|
if (!fieldContainsCyrillicCharacters(pairedField)) {
|
|
237
240
|
return false;
|
|
238
241
|
}
|
|
@@ -245,7 +248,7 @@ export default function(config = {}) {
|
|
|
245
248
|
const field1 = fieldToString(createFieldForSfs4900Comparison(field, field.tag));
|
|
246
249
|
nvdebug(`COMPARE CONTENTS:
|
|
247
250
|
'${field1}' vs
|
|
248
|
-
'${field2}': ${field1 === field2 ? "OK" : "FAIL"}
|
|
251
|
+
'${field2}': ${field1 === field2 ? "OK" : "FAIL"}`, debugDev);
|
|
249
252
|
return field1 === field2;
|
|
250
253
|
}
|
|
251
254
|
function createFieldForSfs4900Comparison(field, tag) {
|
package/dist/cyrillux.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cyrillux.js"],
|
|
4
|
-
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport XRegExp from 'xregexp';\nimport * as iso9 from '@natlibfi/iso9-1995';\nimport * as sfs4900 from '@natlibfi/sfs-4900';\nimport {fieldHasSubfield, fieldToString, fieldsToString, isContentSubfieldCode, nvdebug} from './utils.js';\nimport {fieldGetMaxSubfield6OccurrenceNumberAsInteger, fieldGetOccurrenceNumberPairs, fieldGetUnambiguousOccurrenceNumber, intToOccurrenceNumberString, recordGetMaxSubfield6OccurrenceNumberAsInteger, resetSubfield6Tag} from './subfield6Utils.js';\nimport {default as sortFields} from './sortFields.js';\nimport {default as reindexSubfield6OccurenceNumbers} from './reindexSubfield6OccurenceNumbers.js';\nimport {fieldStripPunctuation} from './punctuation2.js';\nimport {getLanguageCode} from './addMissingField041.js';\n\nconst iso9Trans = 'ISO9 <TRANS>';\nconst cyrillicTrans = 'CYRILLIC <TRANS>';\nconst sfs4900Trans = 'SFS4900 <TRANS>';\n\nexport default function (config = {}) {\n // console.log(`CONFIG=${JSON.stringify(config)}`); // eslint-disable-line no-console\n\n return {\n description: 'Cyrillux functionality: convert original field to latinitsa (ISO-9) and add 880s for original cyrillic and latinitsa (SFS-4900)',\n validate, fix\n };\n\n function preprocessConfig() {\n config.retainCyrillic = typeof config.retainCyrillic === 'undefined' ? true : config.retainCyrillic;\n config.doISO9Transliteration = typeof config.doISO9Transliteration === 'undefined' ? true : config.doISO9Transliteration;\n config.doSFS4900Transliteration = typeof config.doSFS4900Transliteration === 'undefined' ? true : config.doSFS4900Transliteration;\n config.preferSFS4900 = setPreference();\n\n function setPreference() {\n if (!config.doSFS4900Transliteration) {\n return false;\n }\n if (!config.doISO9Transliteration && config.doSFS4900Transliteration) {\n return true;\n }\n if (typeof config.preferSFS4900 === 'undefined') {\n return false;\n }\n return config.preferSFS4900;\n }\n }\n\n function fix(record) {\n // console.log(`FIX has CONFIG=${JSON.stringify(config)}`); // eslint-disable-line no-console\n // Fix always succeeds\n const res = {message: [], fix: [], valid: true};\n\n preprocessConfig();\n\n const nBefore = record.fields.length;\n\n record.fields = processFields(record.fields);\n\n if (nBefore < record.fields.length) {\n reindexSubfield6OccurenceNumbers().fix(record);\n sortFields().fix(record);\n }\n\n function processFields(input, output = []) {\n const [currField, ...remainingInput] = input;\n if (!currField) {\n return output;\n }\n\n const fakeRecord = {fields: output};\n const createdMax = recordGetMaxSubfield6OccurrenceNumberAsInteger(fakeRecord);\n const result = processField(currField, record, createdMax);\n\n return processFields(remainingInput, [...output, ...result]);\n }\n\n return res;\n }\n\n function validate(record) {\n const res = {message: [], valid: true};\n\n preprocessConfig();\n\n record.fields?.forEach(field => {\n validateField(field, res, record);\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n\n function validateField(field, res, record) {\n const orig = fieldToString(field);\n\n const normalizedFields = processField(clone(field), record);\n const mod = fieldsToString(normalizedFields).replace(/\\t__SEPARATOR__\\t/ug, ', ').replace(/ (\u20216 [0-9][0-9][0-9])-[0-9][0-9]+/gu, ' $1-NN');\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`CHANGE: ${orig} => ${mod}`);\n return;\n }\n return;\n }\n\n function isCyrillicCharacter(char) {\n return XRegExp('[\\\\p{Cyrillic}]').test(char);\n }\n\n function containsCyrillicCharacters(str) { // from melinda-ui-cyrillux\n if (!str) {\n return false;\n }\n return str.split('').some(isCyrillicCharacter);\n }\n\n function fieldContainsCyrillicCharacters(field) { // based on melinda-ui-cyrillux\n return field.subfields && field.subfields.some(sf => subfieldRequiresTransliteration(sf, field.tag));\n }\n\n function subfieldRequiresTransliteration(subfield, tag = undefined) {\n if (!isContentSubfieldCode(subfield.code, tag)) {\n return false;\n }\n return containsCyrillicCharacters(subfield.value);\n }\n\n function tagCanBeTransliterated(tag) {\n // Use this to filter out \"(0..)\" etc\n if (config.tagPattern && !tag.match(config.tagPattern)) {\n return false;\n }\n // These are hard-coded, and will fail anyway:\n return !['336', '337', '338', '880'].includes(tag);\n }\n\n function fieldCanBeTransliterated(field) {\n // Skip certain tags ('880' is the actual skip-me beef here, but we have seen other no-nos as well).\n // Discussion: We should probably also skip others like 05X-08X, 648, 650, 651, and 655, but this needs thinking...\n // Also I'd like to convert do CYRILLIC->ISO-9 in field 300 (and others?) without 880 mappings... (<- not implemented)\n\n // nvdebug(`fieldCanBeTransliterated('${fieldToString(field)}') in...`);\n if (!tagCanBeTransliterated(field.tag)) {\n return false;\n }\n\n if (!config.doISO9Transliteration && !config.doSFS4900Transliteration) {\n return false;\n }\n\n // Skip control fields:\n if (!field.subfields) {\n return false;\n }\n // When doing MELINDA-10330-ish, we noticed that $6 should not prevent translittaration per se, so this restriction is no longer applied!\n\n if (field.subfields.some(sf => sf.code === '9' && sf.value.includes('<TRANS>'))) {\n return false;\n }\n\n return fieldContainsCyrillicCharacters(field); // We have something to translitterate:\n }\n\n\n function mapSubfieldToIso9(subfield, tag) {\n if (!subfieldRequiresTransliteration(subfield, tag)) {\n return {code: subfield.code, value: subfield.value}; // just clone\n }\n\n const conversionResult = iso9.convertToLatin(subfield.value);\n\n return {code: subfield.code, value: conversionResult.result};\n }\n\n function mapSubfieldToSfs4900(subfield, tag, lang = 'rus') {\n const inputLang = lang === 'ukr' ? 'ukr' : 'rus'; // Support 'ukr' and 'rus', default to 'rus'\n if (!subfieldRequiresTransliteration(subfield, tag)) {\n return {code: subfield.code, value: subfield.value};\n }\n const conversionResult = sfs4900.convertToLatin(subfield.value, inputLang);\n\n console.log(JSON.stringify(conversionResult));\n const result = conversionResult.result;\n console.log(JSON.stringify(result));\n //console.log(`VAL: ${subfield.value} => ${value} using ${lang}`); // eslint-disable-line no-console\n return {code: subfield.code, value: result};\n }\n\n function mapField(field, occurrenceNumber, iso9 = true, lang = 'rus') {\n const subfield6 = deriveSubfield6('880', field.subfields, occurrenceNumber);\n const transliterationText = iso9 ? iso9Trans : sfs4900Trans;\n\n const subfield9 = fieldHasSubfield(field, '9', transliterationText) ? [] : [{code: '9', value: transliterationText}]; // Add only if needed\n const transliterationFunc = iso9 ? mapSubfieldToIso9 : mapSubfieldToSfs4900;\n\n // NB! iso9 won't use lang\n const subfields = field.subfields.filter(sf => sf.code !== '6').map(sf => transliterationFunc(sf, field.tag, lang));\n\n const newField = {tag: field.tag, ind1: field.ind1, ind2: field.ind2, subfields: [subfield6, ...subfields, ...subfield9]};\n\n // Transliteration goes to the original field:\n if (!iso9 && config.preferSFS4900) {\n return newField;\n }\n if (iso9 && !config.preferSFS4900) {\n return newField;\n }\n // Translitetation goes to field 880:\n\n //const subfield6 = newField.subfields.find(sf => sf.code === '6');\n newField.tag = '880';\n resetSubfield6Tag(subfield6, field.tag);\n return newField;\n\n }\n\n function mapFieldToIso9(field, occurrenceNumber) {\n if (!config.doISO9Transliteration) {\n return undefined;\n }\n // Just converts the field to ISO-9 latinitsa, does not create any field-880s, so don't bother with $6 or $9 either\n if (!config.retainCyrillic && !config.preferSFS4900) {\n const subfields = field.subfields.map(sf => mapSubfieldToIso9(sf, field.tag));\n return {tag: field.tag, ind1: field.ind1, ind2: field.ind2, subfields};\n }\n\n return mapField(field, occurrenceNumber, true, 'rus');\n\n }\n\n function mapFieldToSfs4900(field, occurrenceNumber, lang = 'rus') {\n if (!config.doSFS4900Transliteration) {\n return undefined;\n }\n // Just converts the field to SFS-4900 latinitsa, does not create any field-880s, so don't bother with $6 or $9 either\n if (!config.retainCyrillic && config.preferSFS4900) {\n const subfields = field.subfields.map(sf => mapSubfieldToSfs4900(sf, field.tag, lang));\n return {tag: field.tag, ind1: field.ind1, ind2: field.ind2, subfields};\n }\n\n return mapField(field, occurrenceNumber, false, lang);\n }\n\n function deriveSubfield6(tag, subfields, occurrenceNumber) {\n const initialSubfield = {code: '6', value: `${tag}-${occurrenceNumber}`};\n if (tag === '880') { // If *tag in subfield $6* is 880, field is not 880 :D\n return initialSubfield;\n }\n // Try to use existing subfield\n const [subfield6] = subfields.filter(sf => sf.code === '6').map(sf => clone(sf));\n if (subfield6) {\n resetSubfield6Tag(subfield6, tag); // Should we update occurrence number?\n return subfield6;\n }\n\n return initialSubfield;\n }\n\n function mapFieldToCyrillicField880(field, occurrenceNumber) {\n if (!config.retainCyrillic) {\n return undefined;\n }\n nvdebug(`Derive CYR 880 from ${fieldToString(field)}`);\n const newSubfield6 = deriveSubfield6(field.tag, field.subfields, occurrenceNumber);\n const newSubfield9 = fieldHasSubfield(field, '9', cyrillicTrans) ? [] : [{code: '9', value: cyrillicTrans}];\n const subfields = [\n newSubfield6,\n ...field.subfields.filter(sf => sf.code !== '6').map(sf => clone(sf)),\n ...newSubfield9\n ];\n\n const newField = {tag: '880', ind1: field.ind1, ind2: field.ind2, subfields};\n nvdebug(` New CYR 880 ${fieldToString(newField)}`);\n return newField;\n }\n\n\n function getNewOccurrenceNumber(originalField, record, maxCreatedOccurrenceNumber = 0) {\n const occurrenceNumber = fieldGetMaxSubfield6OccurrenceNumberAsInteger(originalField);\n // Return existing occurrence number:\n if (occurrenceNumber > 0) {\n return occurrenceNumber;\n }\n if (maxCreatedOccurrenceNumber) {\n return maxCreatedOccurrenceNumber + 1;\n }\n return recordGetMaxSubfield6OccurrenceNumberAsInteger(record) + 1;\n }\n\n function retainCyrillic(existingPairedFields) {\n // Should we move cyrillic content from a normali field to a 880?\n if (!config.retainCyrillic) {\n return false;\n }\n // Fail if we already have a paired 880 $9 <CYRILLIC> TRANS\n return !existingPairedFields.some(f => fieldHasSubfield(f, '9', cyrillicTrans));\n }\n\n function needsSfs4900Transliteration(existingPairedFields) {\n if (!config.doSFS4900Transliteration) {\n return false;\n }\n return !existingPairedFields.some(f => fieldHasSubfield(f, '9', sfs4900Trans));\n }\n\n function sfs4900PairCanBeTransliterated(field, record) {\n // MELINDA-10330: we already have public library data: (unmarked) SFS-4900 in FIELD and (unmarked) Cyrillic in 880\n if (!field.subfields || !tagCanBeTransliterated(field.tag) || !config.doISO9Transliteration || !config.retainCyrillic || !config.doSFS4900Transliteration) {\n return false;\n }\n\n // Original field: $9 ISO9 <TRANS> is the only legal <TRANS>\n if (fieldContainsCyrillicCharacters(field) || field.subfields.some(sf => sf.code === '9' && sf.value.includes('<TRANS>') && sf.value !== iso9Trans)) {\n return false;\n }\n\n const existingPairedFields = fieldGetOccurrenceNumberPairs(field, record.get('880'));\n if (existingPairedFields.length !== 1) {\n return false;\n }\n\n // Paired field: $9 CYRILLIC <TRANS> is the only legal <TRANS>\n const [pairedField] = existingPairedFields;\n nvdebug(`LOOKING FOR SFS4900 PAIR: ${fieldToString(field)}`);\n nvdebug(` HAVING PAIRED FIELD: ${fieldToString(pairedField)}`);\n if (!fieldContainsCyrillicCharacters(pairedField)) {\n return false;\n }\n if (pairedField.subfields.some(sf => sf.code === '9' && sf.value.includes('<TRANS>') && sf.value !== cyrillicTrans)) {\n return false;\n }\n\n // Actually check that original field and and sfs-4900-fied cyrillic field are equal (after punctuation clean-up),\n // and thus it's a real case of MELINDA-10330 ISO9 adding:\n const occurrenceNumberAsString = fieldGetUnambiguousOccurrenceNumber(field);\n const languageCode = getLanguageCode(record);\n const field2 = fieldToString(createFieldForSfs4900Comparison(mapFieldToSfs4900(pairedField, occurrenceNumberAsString, languageCode), field.tag));\n const field1 = fieldToString(createFieldForSfs4900Comparison(field, field.tag));\n nvdebug(`COMPARE CONTENTS:\\n '${field1}' vs\\n '${field2}': ${field1 === field2 ? 'OK' : 'FAIL'}`);\n return field1 === field2;\n }\n\n function createFieldForSfs4900Comparison(field, tag) {\n const clonedField = clone(field);\n clonedField.tag = tag;\n clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== '9' || sf.value !== sfs4900Trans);\n return fieldStripPunctuation(clonedField);\n }\n\n function transliterateSfs4900Pair(field, record) {\n // Handle MELINDA-10330: Field is already in SFS-4900 and the only paired field is in Cyrillic!\n if (!config.doISO9Transliteration) {\n return [];\n }\n const [pairedField] = fieldGetOccurrenceNumberPairs(field, record.get('880'));\n\n const occurrenceNumberAsString = fieldGetUnambiguousOccurrenceNumber(field);\n const languageCode = getLanguageCode(record);\n\n const tmpField = {'tag': field.tag, 'ind1': field.ind1, 'ind2': field.ind2, 'subfields': pairedField.subfields};\n\n const newMainField = config.doISO9Transliteration ? mapFieldToIso9(tmpField, occurrenceNumberAsString) : undefined; // Cyrillic => ISO-9\n const newCyrillicField = config.retainCyrillic ? mapFieldToCyrillicField880(tmpField, occurrenceNumberAsString) : undefined; // CYRILLIC\n const newSFS4900Field = config.doSFS4900Transliteration ? mapFieldToSfs4900(field, occurrenceNumberAsString, languageCode) : undefined; // SFS-4900\n\n // Trigger the drop of original counterpart $6 :\n pairedField.cyrilluxSkip = 1;\n\n return [newMainField, newCyrillicField, newSFS4900Field].filter(f => f);\n }\n\n\n function processField(originalField, record, maxCreatedOccurrenceNumber = 0) {\n if (!fieldCanBeTransliterated(originalField)) {\n if (sfs4900PairCanBeTransliterated(originalField, record)) { // MELINDA-10330\n return transliterateSfs4900Pair(originalField, record);\n }\n if (originalField.cyrilluxSkip) { // MELINDA-10330 hack to remove 880 fields that were replaced/sort-of processed with their counterpair.\n return [];\n }\n return [originalField];\n }\n\n // nvdebug(`PROCESSING: ${fieldToString(originalField)}`);\n\n const newOccurrenceNumberAsInt = getNewOccurrenceNumber(originalField, record, maxCreatedOccurrenceNumber);\n const newOccurrenceNumberAsString = intToOccurrenceNumberString(newOccurrenceNumberAsInt);\n const languageCode = getLanguageCode(record);\n\n // nvdebug(`NEW OCCURRENCE NUMBER: '${newOccurrenceNumberAsString}'`);\n\n const existingPairedFields = fieldGetOccurrenceNumberPairs(originalField, record.get('880'));\n\n // nvdebug(`NUMBER OF PAIRED 880 FIELDS: ${existingPairedFields.length}`);\n\n const newMainField = mapFieldToIso9(originalField, newOccurrenceNumberAsString); // ISO-9\n const newCyrillicField = retainCyrillic(existingPairedFields) ? mapFieldToCyrillicField880(originalField, newOccurrenceNumberAsString) : undefined; // CYRILLIC\n const newSFS4900Field = needsSfs4900Transliteration(existingPairedFields) ? mapFieldToSfs4900(originalField, newOccurrenceNumberAsString, languageCode) : undefined; /// SFS-4900\n\n return [newMainField, newCyrillicField, newSFS4900Field].filter(f => f);\n }\n}\n"],
|
|
5
|
-
"mappings": "AACA,OAAO,WAAW;AAClB,OAAO,aAAa;AACpB,YAAY,UAAU;AACtB,YAAY,aAAa;AACzB,SAAQ,kBAAkB,eAAe,gBAAgB,uBAAuB,eAAc;AAC9F,SAAQ,+CAA+C,+BAA+B,qCAAqC,6BAA6B,gDAAgD,yBAAwB;AAChO,SAAQ,WAAW,kBAAiB;AACpC,SAAQ,WAAW,wCAAuC;AAC1D,SAAQ,6BAA4B;AACpC,SAAQ,uBAAsB;AAE9B,MAAM,YAAY;AAClB,MAAM,gBAAgB;AACtB,MAAM,eAAe;
|
|
4
|
+
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport clone from 'clone';\nimport XRegExp from 'xregexp';\nimport * as iso9 from '@natlibfi/iso9-1995';\nimport * as sfs4900 from '@natlibfi/sfs-4900';\nimport {fieldHasSubfield, fieldToString, fieldsToString, isContentSubfieldCode, nvdebug} from './utils.js';\nimport {fieldGetMaxSubfield6OccurrenceNumberAsInteger, fieldGetOccurrenceNumberPairs, fieldGetUnambiguousOccurrenceNumber, intToOccurrenceNumberString, recordGetMaxSubfield6OccurrenceNumberAsInteger, resetSubfield6Tag} from './subfield6Utils.js';\nimport {default as sortFields} from './sortFields.js';\nimport {default as reindexSubfield6OccurenceNumbers} from './reindexSubfield6OccurenceNumbers.js';\nimport {fieldStripPunctuation} from './punctuation2.js';\nimport {getLanguageCode} from './addMissingField041.js';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/cyrillux');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst iso9Trans = 'ISO9 <TRANS>';\nconst cyrillicTrans = 'CYRILLIC <TRANS>';\nconst sfs4900Trans = 'SFS4900 <TRANS>';\n\n// eslint-disable-next-line max-lines-per-function\nexport default function (config = {}) {\n // console.log(`CONFIG=${JSON.stringify(config)}`); // eslint-disable-line no-console\n\n return {\n description: 'Cyrillux functionality: convert original field to latinitsa (ISO-9) and add 880s for original cyrillic and latinitsa (SFS-4900)',\n validate, fix\n };\n\n function preprocessConfig() {\n config.retainCyrillic = typeof config.retainCyrillic === 'undefined' ? true : config.retainCyrillic;\n config.doISO9Transliteration = typeof config.doISO9Transliteration === 'undefined' ? true : config.doISO9Transliteration;\n config.doSFS4900Transliteration = typeof config.doSFS4900Transliteration === 'undefined' ? true : config.doSFS4900Transliteration;\n config.preferSFS4900 = setPreference();\n\n function setPreference() {\n if (!config.doSFS4900Transliteration) {\n return false;\n }\n if (!config.doISO9Transliteration && config.doSFS4900Transliteration) {\n return true;\n }\n if (typeof config.preferSFS4900 === 'undefined') {\n return false;\n }\n return config.preferSFS4900;\n }\n }\n\n function fix(record) {\n // console.log(`FIX has CONFIG=${JSON.stringify(config)}`); // eslint-disable-line no-console\n // Fix always succeeds\n const res = {message: [], fix: [], valid: true};\n\n preprocessConfig();\n\n const nBefore = record.fields.length;\n\n record.fields = processFields(record.fields);\n\n if (nBefore < record.fields.length) {\n reindexSubfield6OccurenceNumbers().fix(record);\n sortFields().fix(record);\n }\n\n function processFields(input, output = []) {\n const [currField, ...remainingInput] = input;\n if (!currField) {\n return output;\n }\n\n const fakeRecord = {fields: output};\n const createdMax = recordGetMaxSubfield6OccurrenceNumberAsInteger(fakeRecord);\n const result = processField(currField, record, createdMax);\n\n return processFields(remainingInput, [...output, ...result]);\n }\n\n return res;\n }\n\n function validate(record) {\n const res = {message: [], valid: true};\n\n preprocessConfig();\n\n record.fields?.forEach(field => {\n validateField(field, res, record);\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n\n function validateField(field, res, record) {\n const orig = fieldToString(field);\n\n const normalizedFields = processField(clone(field), record);\n const mod = fieldsToString(normalizedFields).replace(/\\t__SEPARATOR__\\t/ug, ', ').replace(/ (\u20216 [0-9][0-9][0-9])-[0-9][0-9]+/gu, ' $1-NN');\n if (orig !== mod) { // Fail as the input is \"broken\"/\"crap\"/sumthing\n res.message.push(`CHANGE: ${orig} => ${mod}`);\n return;\n }\n return;\n }\n\n function isCyrillicCharacter(char) {\n return XRegExp('[\\\\p{Cyrillic}]').test(char);\n }\n\n function containsCyrillicCharacters(str) { // from melinda-ui-cyrillux\n if (!str) {\n return false;\n }\n return str.split('').some(isCyrillicCharacter);\n }\n\n function fieldContainsCyrillicCharacters(field) { // based on melinda-ui-cyrillux\n return field.subfields && field.subfields.some(sf => subfieldRequiresTransliteration(sf, field.tag));\n }\n\n function subfieldRequiresTransliteration(subfield, tag = undefined) {\n if (!isContentSubfieldCode(subfield.code, tag)) {\n return false;\n }\n return containsCyrillicCharacters(subfield.value);\n }\n\n function tagCanBeTransliterated(tag) {\n // Use this to filter out \"(0..)\" etc\n if (config.tagPattern && !tag.match(config.tagPattern)) {\n return false;\n }\n // These are hard-coded, and will fail anyway:\n return !['336', '337', '338', '880'].includes(tag);\n }\n\n function fieldCanBeTransliterated(field) {\n // Skip certain tags ('880' is the actual skip-me beef here, but we have seen other no-nos as well).\n // Discussion: We should probably also skip others like 05X-08X, 648, 650, 651, and 655, but this needs thinking...\n // Also I'd like to convert do CYRILLIC->ISO-9 in field 300 (and others?) without 880 mappings... (<- not implemented)\n\n // nvdebug(`fieldCanBeTransliterated('${fieldToString(field)}') in...`, debugDev);\n if (!tagCanBeTransliterated(field.tag)) {\n return false;\n }\n\n if (!config.doISO9Transliteration && !config.doSFS4900Transliteration) {\n return false;\n }\n\n // Skip control fields:\n if (!field.subfields) {\n return false;\n }\n // When doing MELINDA-10330-ish, we noticed that $6 should not prevent translittaration per se, so this restriction is no longer applied!\n\n if (field.subfields.some(sf => sf.code === '9' && sf.value.includes('<TRANS>'))) {\n return false;\n }\n\n return fieldContainsCyrillicCharacters(field); // We have something to translitterate:\n }\n\n\n function mapSubfieldToIso9(subfield, tag) {\n if (!subfieldRequiresTransliteration(subfield, tag)) {\n return {code: subfield.code, value: subfield.value}; // just clone\n }\n\n const conversionResult = iso9.convertToLatin(subfield.value);\n\n return {code: subfield.code, value: conversionResult.result};\n }\n\n function mapSubfieldToSfs4900(subfield, tag, lang = 'rus') {\n const inputLang = lang === 'ukr' ? 'ukr' : 'rus'; // Support 'ukr' and 'rus', default to 'rus'\n if (!subfieldRequiresTransliteration(subfield, tag)) {\n return {code: subfield.code, value: subfield.value};\n }\n const conversionResult = sfs4900.convertToLatin(subfield.value, inputLang);\n\n nvdebug(`${JSON.stringify(conversionResult)}`, debugDev);\n const result = conversionResult.result;\n nvdebug(`${JSON.stringify(result)}`, debugDev);\n //nvdebug(`VAL: ${subfield.value} => ${value} using ${lang}`, debugDev);\n return {code: subfield.code, value: result};\n }\n\n function mapField(field, occurrenceNumber, iso9 = true, lang = 'rus') {\n const subfield6 = deriveSubfield6('880', field.subfields, occurrenceNumber);\n const transliterationText = iso9 ? iso9Trans : sfs4900Trans;\n\n const subfield9 = fieldHasSubfield(field, '9', transliterationText) ? [] : [{code: '9', value: transliterationText}]; // Add only if needed\n const transliterationFunc = iso9 ? mapSubfieldToIso9 : mapSubfieldToSfs4900;\n\n // NB! iso9 won't use lang\n const subfields = field.subfields.filter(sf => sf.code !== '6').map(sf => transliterationFunc(sf, field.tag, lang));\n\n const newField = {tag: field.tag, ind1: field.ind1, ind2: field.ind2, subfields: [subfield6, ...subfields, ...subfield9]};\n\n // Transliteration goes to the original field:\n if (!iso9 && config.preferSFS4900) {\n return newField;\n }\n if (iso9 && !config.preferSFS4900) {\n return newField;\n }\n // Translitetation goes to field 880:\n\n //const subfield6 = newField.subfields.find(sf => sf.code === '6');\n newField.tag = '880';\n resetSubfield6Tag(subfield6, field.tag);\n return newField;\n\n }\n\n function mapFieldToIso9(field, occurrenceNumber) {\n if (!config.doISO9Transliteration) {\n return undefined;\n }\n // Just converts the field to ISO-9 latinitsa, does not create any field-880s, so don't bother with $6 or $9 either\n if (!config.retainCyrillic && !config.preferSFS4900) {\n const subfields = field.subfields.map(sf => mapSubfieldToIso9(sf, field.tag));\n return {tag: field.tag, ind1: field.ind1, ind2: field.ind2, subfields};\n }\n\n return mapField(field, occurrenceNumber, true, 'rus');\n\n }\n\n function mapFieldToSfs4900(field, occurrenceNumber, lang = 'rus') {\n if (!config.doSFS4900Transliteration) {\n return undefined;\n }\n // Just converts the field to SFS-4900 latinitsa, does not create any field-880s, so don't bother with $6 or $9 either\n if (!config.retainCyrillic && config.preferSFS4900) {\n const subfields = field.subfields.map(sf => mapSubfieldToSfs4900(sf, field.tag, lang));\n return {tag: field.tag, ind1: field.ind1, ind2: field.ind2, subfields};\n }\n\n return mapField(field, occurrenceNumber, false, lang);\n }\n\n function deriveSubfield6(tag, subfields, occurrenceNumber) {\n const initialSubfield = {code: '6', value: `${tag}-${occurrenceNumber}`};\n if (tag === '880') { // If *tag in subfield $6* is 880, field is not 880 :D\n return initialSubfield;\n }\n // Try to use existing subfield\n const [subfield6] = subfields.filter(sf => sf.code === '6').map(sf => clone(sf));\n if (subfield6) {\n resetSubfield6Tag(subfield6, tag); // Should we update occurrence number?\n return subfield6;\n }\n\n return initialSubfield;\n }\n\n function mapFieldToCyrillicField880(field, occurrenceNumber) {\n if (!config.retainCyrillic) {\n return undefined;\n }\n nvdebug(`Derive CYR 880 from ${fieldToString(field)}`, debugDev);\n const newSubfield6 = deriveSubfield6(field.tag, field.subfields, occurrenceNumber);\n const newSubfield9 = fieldHasSubfield(field, '9', cyrillicTrans) ? [] : [{code: '9', value: cyrillicTrans}];\n const subfields = [\n newSubfield6,\n ...field.subfields.filter(sf => sf.code !== '6').map(sf => clone(sf)),\n ...newSubfield9\n ];\n\n const newField = {tag: '880', ind1: field.ind1, ind2: field.ind2, subfields};\n nvdebug(` New CYR 880 ${fieldToString(newField)}`, debugDev);\n return newField;\n }\n\n\n function getNewOccurrenceNumber(originalField, record, maxCreatedOccurrenceNumber = 0) {\n const occurrenceNumber = fieldGetMaxSubfield6OccurrenceNumberAsInteger(originalField);\n // Return existing occurrence number:\n if (occurrenceNumber > 0) {\n return occurrenceNumber;\n }\n if (maxCreatedOccurrenceNumber) {\n return maxCreatedOccurrenceNumber + 1;\n }\n return recordGetMaxSubfield6OccurrenceNumberAsInteger(record) + 1;\n }\n\n function retainCyrillic(existingPairedFields) {\n // Should we move cyrillic content from a normali field to a 880?\n if (!config.retainCyrillic) {\n return false;\n }\n // Fail if we already have a paired 880 $9 <CYRILLIC> TRANS\n return !existingPairedFields.some(f => fieldHasSubfield(f, '9', cyrillicTrans));\n }\n\n function needsSfs4900Transliteration(existingPairedFields) {\n if (!config.doSFS4900Transliteration) {\n return false;\n }\n return !existingPairedFields.some(f => fieldHasSubfield(f, '9', sfs4900Trans));\n }\n\n function sfs4900PairCanBeTransliterated(field, record) {\n // MELINDA-10330: we already have public library data: (unmarked) SFS-4900 in FIELD and (unmarked) Cyrillic in 880\n if (!field.subfields || !tagCanBeTransliterated(field.tag) || !config.doISO9Transliteration || !config.retainCyrillic || !config.doSFS4900Transliteration) {\n return false;\n }\n\n // Original field: $9 ISO9 <TRANS> is the only legal <TRANS>\n if (fieldContainsCyrillicCharacters(field) || field.subfields.some(sf => sf.code === '9' && sf.value.includes('<TRANS>') && sf.value !== iso9Trans)) {\n return false;\n }\n\n const existingPairedFields = fieldGetOccurrenceNumberPairs(field, record.get('880'));\n if (existingPairedFields.length !== 1) {\n return false;\n }\n\n // Paired field: $9 CYRILLIC <TRANS> is the only legal <TRANS>\n const [pairedField] = existingPairedFields;\n nvdebug(`LOOKING FOR SFS4900 PAIR: ${fieldToString(field)}`, debugDev);\n nvdebug(` HAVING PAIRED FIELD: ${fieldToString(pairedField)}`, debugDev);\n if (!fieldContainsCyrillicCharacters(pairedField)) {\n return false;\n }\n if (pairedField.subfields.some(sf => sf.code === '9' && sf.value.includes('<TRANS>') && sf.value !== cyrillicTrans)) {\n return false;\n }\n\n // Actually check that original field and and sfs-4900-fied cyrillic field are equal (after punctuation clean-up),\n // and thus it's a real case of MELINDA-10330 ISO9 adding:\n const occurrenceNumberAsString = fieldGetUnambiguousOccurrenceNumber(field);\n const languageCode = getLanguageCode(record);\n const field2 = fieldToString(createFieldForSfs4900Comparison(mapFieldToSfs4900(pairedField, occurrenceNumberAsString, languageCode), field.tag));\n const field1 = fieldToString(createFieldForSfs4900Comparison(field, field.tag));\n nvdebug(`COMPARE CONTENTS:\\n '${field1}' vs\\n '${field2}': ${field1 === field2 ? 'OK' : 'FAIL'}`, debugDev);\n return field1 === field2;\n }\n\n function createFieldForSfs4900Comparison(field, tag) {\n const clonedField = clone(field);\n clonedField.tag = tag;\n clonedField.subfields = clonedField.subfields.filter(sf => sf.code !== '9' || sf.value !== sfs4900Trans);\n return fieldStripPunctuation(clonedField);\n }\n\n function transliterateSfs4900Pair(field, record) {\n // Handle MELINDA-10330: Field is already in SFS-4900 and the only paired field is in Cyrillic!\n if (!config.doISO9Transliteration) {\n return [];\n }\n const [pairedField] = fieldGetOccurrenceNumberPairs(field, record.get('880'));\n\n const occurrenceNumberAsString = fieldGetUnambiguousOccurrenceNumber(field);\n const languageCode = getLanguageCode(record);\n\n const tmpField = {'tag': field.tag, 'ind1': field.ind1, 'ind2': field.ind2, 'subfields': pairedField.subfields};\n\n const newMainField = config.doISO9Transliteration ? mapFieldToIso9(tmpField, occurrenceNumberAsString) : undefined; // Cyrillic => ISO-9\n const newCyrillicField = config.retainCyrillic ? mapFieldToCyrillicField880(tmpField, occurrenceNumberAsString) : undefined; // CYRILLIC\n const newSFS4900Field = config.doSFS4900Transliteration ? mapFieldToSfs4900(field, occurrenceNumberAsString, languageCode) : undefined; // SFS-4900\n\n // Trigger the drop of original counterpart $6 :\n pairedField.cyrilluxSkip = 1;\n\n return [newMainField, newCyrillicField, newSFS4900Field].filter(f => f);\n }\n\n\n function processField(originalField, record, maxCreatedOccurrenceNumber = 0) {\n if (!fieldCanBeTransliterated(originalField)) {\n if (sfs4900PairCanBeTransliterated(originalField, record)) { // MELINDA-10330\n return transliterateSfs4900Pair(originalField, record);\n }\n if (originalField.cyrilluxSkip) { // MELINDA-10330 hack to remove 880 fields that were replaced/sort-of processed with their counterpair.\n return [];\n }\n return [originalField];\n }\n\n // nvdebug(`PROCESSING: ${fieldToString(originalField)}`, debugDev);\n\n const newOccurrenceNumberAsInt = getNewOccurrenceNumber(originalField, record, maxCreatedOccurrenceNumber);\n const newOccurrenceNumberAsString = intToOccurrenceNumberString(newOccurrenceNumberAsInt);\n const languageCode = getLanguageCode(record);\n\n // nvdebug(`NEW OCCURRENCE NUMBER: '${newOccurrenceNumberAsString}'`, debugDev);\n\n const existingPairedFields = fieldGetOccurrenceNumberPairs(originalField, record.get('880'));\n\n // nvdebug(`NUMBER OF PAIRED 880 FIELDS: ${existingPairedFields.length}`, debugDev);\n\n const newMainField = mapFieldToIso9(originalField, newOccurrenceNumberAsString); // ISO-9\n const newCyrillicField = retainCyrillic(existingPairedFields) ? mapFieldToCyrillicField880(originalField, newOccurrenceNumberAsString) : undefined; // CYRILLIC\n const newSFS4900Field = needsSfs4900Transliteration(existingPairedFields) ? mapFieldToSfs4900(originalField, newOccurrenceNumberAsString, languageCode) : undefined; /// SFS-4900\n\n return [newMainField, newCyrillicField, newSFS4900Field].filter(f => f);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["iso9"]
|
|
7
7
|
}
|
|
@@ -6,6 +6,7 @@ import clone from "clone";
|
|
|
6
6
|
import { default as createNatlibfiSruClient } from "@natlibfi/sru-client";
|
|
7
7
|
import { fieldFixPunctuation } from "./punctuation2.js";
|
|
8
8
|
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:disambiguateSeriesStatements");
|
|
9
|
+
const debugDev = debug.extend("dev");
|
|
9
10
|
const ELECTRONIC = 1;
|
|
10
11
|
const PRINTED = 2;
|
|
11
12
|
const NEITHER_OR_UNKNOWN = 0;
|
|
@@ -56,7 +57,7 @@ export default function() {
|
|
|
56
57
|
return fix490x(recordType, remainingFields, reallyFix, message);
|
|
57
58
|
}
|
|
58
59
|
const deletableStrings = deletableXs.map((sf) => subfieldToString(sf));
|
|
59
|
-
nvdebug(`Field has removable ISSNS: '${deletableStrings.join(", ")}`,
|
|
60
|
+
nvdebug(`Field has removable ISSNS: '${deletableStrings.join(", ")}`, debugDev);
|
|
60
61
|
if (reallyFix) {
|
|
61
62
|
currField.subfields = currField.subfields.filter((sf) => !deletableStrings.includes(subfieldToString(sf)));
|
|
62
63
|
fieldFixPunctuation(currField);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/disambiguateSeriesStatements.js"],
|
|
4
|
-
"sourcesContent": ["import createDebugLogger from 'debug';\nimport {fieldToString, nvdebug, subfieldToString} from './utils.js';\nimport {MARCXML} from '@natlibfi/marc-record-serializers';\nimport {Error} from '@natlibfi/melinda-commons';\nimport clone from 'clone';\nimport {default as createNatlibfiSruClient} from '@natlibfi/sru-client';\nimport {fieldFixPunctuation} from './punctuation2.js';\n\n//const {default: createNatlibfiSruClient} = natlibfiSruClient;\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:disambiguateSeriesStatements');\n\nconst ELECTRONIC = 1;\nconst PRINTED = 2;\nconst NEITHER_OR_UNKNOWN = 0;\nconst SRU_API_URL = 'https://sru.api.melinda.kansalliskirjasto.fi/bib';\n\n// Author(s): Nicholas Volk\nexport default function () {\n const sruClient = createSruClient(SRU_API_URL);\n\n return {\n description: 'Disambiguate between printed and electonic series statements (490 with multiple $xs)',\n validate, fix\n };\n\n async function fix(record) {\n const recordType = getRecordType(record);\n\n const relevantFields = getRelevantFields(record.fields);\n const message = await fix490x(recordType, relevantFields, true);\n\n return {message, fix: [], valid: true};\n }\n\n async function validate(record) {\n const recordType = getRecordType(record);\n\n const relevantFields = getRelevantFields(record.fields);\n const message = await fix490x(recordType, relevantFields, false);\n\n return {message, valid: message.length === 0};\n }\n\n\n function getValidIssnSubfields(field) {\n const subfields = field.subfields?.filter(sf => sf.code === 'x' && sf.value.match(/^[0-9]{4}-[0-9][0-9][0-9][0-9Xx][^0-9Xx]*$/u));\n return subfields;\n }\n\n function isRelevantField(field) {\n if (field.tag !== '490') {\n return false;\n }\n return getValidIssnSubfields(field).length > 1;\n }\n\n function getRelevantFields(fields) {\n return fields.filter(f => isRelevantField(f));\n }\n\n async function fix490x(recordType, fields, reallyFix, message = []) {\n\n if (recordType === NEITHER_OR_UNKNOWN) {\n return message;\n }\n const [currField, ...remainingFields] = fields;\n\n if (!currField) {\n return message;\n }\n\n const validXs = getValidIssnSubfields(currField);\n\n const deletableXs = await getRemovableSubfields(validXs, recordType);\n\n if (deletableXs.length === 0 || deletableXs.length === validXs.length) {\n return fix490x(recordType, remainingFields, reallyFix, message);\n }\n\n const deletableStrings = deletableXs.map(sf => subfieldToString(sf));\n nvdebug(`Field has removable ISSNS: '${deletableStrings.join(', ')}`,
|
|
5
|
-
"mappings": "AAAA,OAAO,uBAAuB;AAC9B,SAAQ,eAAe,SAAS,wBAAuB;AACvD,SAAQ,eAAc;AACtB,SAAQ,aAAY;AACpB,OAAO,WAAW;AAClB,SAAQ,WAAW,+BAA8B;AACjD,SAAQ,2BAA0B;AAIlC,MAAM,QAAQ,kBAAkB,uEAAuE;AAEvG,MAAM,aAAa;AACnB,MAAM,UAAU;AAChB,MAAM,qBAAqB;AAC3B,MAAM,cAAc;
|
|
4
|
+
"sourcesContent": ["import createDebugLogger from 'debug';\nimport {fieldToString, nvdebug, subfieldToString} from './utils.js';\nimport {MARCXML} from '@natlibfi/marc-record-serializers';\nimport {Error} from '@natlibfi/melinda-commons';\nimport clone from 'clone';\nimport {default as createNatlibfiSruClient} from '@natlibfi/sru-client';\nimport {fieldFixPunctuation} from './punctuation2.js';\n\n//const {default: createNatlibfiSruClient} = natlibfiSruClient;\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:disambiguateSeriesStatements');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst ELECTRONIC = 1;\nconst PRINTED = 2;\nconst NEITHER_OR_UNKNOWN = 0;\nconst SRU_API_URL = 'https://sru.api.melinda.kansalliskirjasto.fi/bib';\n\n// Author(s): Nicholas Volk\n// eslint-disable-next-line max-lines-per-function\nexport default function () {\n const sruClient = createSruClient(SRU_API_URL);\n\n return {\n description: 'Disambiguate between printed and electonic series statements (490 with multiple $xs)',\n validate, fix\n };\n\n async function fix(record) {\n const recordType = getRecordType(record);\n\n const relevantFields = getRelevantFields(record.fields);\n const message = await fix490x(recordType, relevantFields, true);\n\n return {message, fix: [], valid: true};\n }\n\n async function validate(record) {\n const recordType = getRecordType(record);\n\n const relevantFields = getRelevantFields(record.fields);\n const message = await fix490x(recordType, relevantFields, false);\n\n return {message, valid: message.length === 0};\n }\n\n\n function getValidIssnSubfields(field) {\n const subfields = field.subfields?.filter(sf => sf.code === 'x' && sf.value.match(/^[0-9]{4}-[0-9][0-9][0-9][0-9Xx][^0-9Xx]*$/u));\n return subfields;\n }\n\n function isRelevantField(field) {\n if (field.tag !== '490') {\n return false;\n }\n return getValidIssnSubfields(field).length > 1;\n }\n\n function getRelevantFields(fields) {\n return fields.filter(f => isRelevantField(f));\n }\n\n async function fix490x(recordType, fields, reallyFix, message = []) {\n\n if (recordType === NEITHER_OR_UNKNOWN) {\n return message;\n }\n const [currField, ...remainingFields] = fields;\n\n if (!currField) {\n return message;\n }\n\n const validXs = getValidIssnSubfields(currField);\n\n const deletableXs = await getRemovableSubfields(validXs, recordType);\n\n if (deletableXs.length === 0 || deletableXs.length === validXs.length) {\n return fix490x(recordType, remainingFields, reallyFix, message);\n }\n\n const deletableStrings = deletableXs.map(sf => subfieldToString(sf));\n nvdebug(`Field has removable ISSNS: '${deletableStrings.join(', ')}`, debugDev);\n\n // fixer:\n if (reallyFix) {\n currField.subfields = currField.subfields.filter(sf => !deletableStrings.includes(subfieldToString(sf)));\n fieldFixPunctuation(currField);\n return fix490x(recordType, remainingFields, reallyFix, message);\n }\n // validators:\n const clonedField = clone(currField);\n const originalString = fieldToString(clonedField);\n clonedField.subfields = clonedField.subfields.filter(sf => !deletableStrings.includes(subfieldToString(sf)));\n\n const newMessage = `Replace '${originalString}' with '${fieldToString(clonedField)}'`;\n\n return fix490x(recordType, remainingFields, reallyFix, [...message, newMessage]);\n }\n\n async function getRemovableSubfields(validXs, recordType, removables = []) {\n const [currSubfield, ...remainingXs] = validXs;\n\n if (!currSubfield) {\n return removables;\n }\n\n const isRemoveable = await isRemovableSubfield(currSubfield, recordType);\n if (isRemoveable) {\n return getRemovableSubfields(remainingXs, recordType, [...removables, currSubfield]);\n }\n return getRemovableSubfields(remainingXs, recordType, removables);\n }\n\n async function isRemovableSubfield(subfield, recordType) {\n //console.info(` isRemovableField() in...`); // eslint-disable-line no-console\n const issn = subfield.value.substring(0, 9); // Strip punctuation (ISSN consists of nine letter, eg. \"1234-5678\")\n\n //console.info(` got ISSN ${issn}`); // eslint-disable-line no-console\n const issnRecords = await issnToRecords(issn);\n //console.info(` ISSN returned ${issnRecords.length} record(s)`); // eslint-disable-line no-console\n\n // !isMismatchingRecord !== isMatchingRecord as NEITHER_OR_UNKNOWN record type is neutral. Thus double negative \"not mismatch\". Sorry about that.\n if (issnRecords.some(r => !isMismatchingRecord(r))) {\n return false;\n }\n return true;\n\n function isMismatchingRecord(r) {\n const issnRecordType = getRecordType(r);\n if (issnRecordType === NEITHER_OR_UNKNOWN) {\n return false;\n }\n return issnRecordType !== recordType;\n }\n }\n\n async function issnToRecords(issn) {\n //console.log('issnToRecords() in...'); // eslint-disable-line no-console\n const records = await search(sruClient, `bath.issn=${issn}`);\n //console.log(`ISSN2RECORDS got ${records.length} record(s)!`); // eslint-disable-line no-console\n return records;\n }\n\n function getRecordType(record) {\n const f337 = record.get('337');\n if (f337.length !== 1) {\n return NEITHER_OR_UNKNOWN;\n }\n\n const b = f337[0].subfields.filter(sf => sf.code === 'b');\n if (b.length !== 1) {\n return NEITHER_OR_UNKNOWN;\n }\n\n if (b[0].value === 'c') {\n return ELECTRONIC;\n }\n\n if (b[0].value === 'n') {\n return PRINTED;\n }\n\n return NEITHER_OR_UNKNOWN;\n }\n\n}\n\n// All the code below is copypasted from melinda-ui-artikkelit project file src/services/sruServices/sruClient.js\n\nexport function createSruClient(sruApiUrl) {\n\n const sruClientOptions = {\n url: sruApiUrl,\n recordSchema: 'marcxml',\n retrieveAll: false,\n maxRecordsPerRequest: 100\n };\n\n return createNatlibfiSruClient(sruClientOptions);\n}\n\n\n/*******************************************************************************/\n/* Search and retrieve (copypaste from melinda-ui-artikkelit) */\n\nexport function search(sruClient, query, one = false) {\n\n return new Promise((resolve, reject) => {\n const promises = [];\n\n const noValidation = {\n fields: false,\n subfields: false,\n subfieldValues: false\n };\n\n // console.info(`SRU query: $${searchUrl}`);\n\n sruClient.searchRetrieve(query)\n .on('record', xmlString => {\n promises.push(MARCXML.from(xmlString, noValidation));\n })\n .on('end', async () => {\n try {\n\n if (promises.length > 0) {\n\n if (one) {\n const [firstPromise] = promises;\n const firstRecord = await firstPromise;\n return resolve(firstRecord);\n }\n\n const records = await Promise.all(promises);\n return resolve(records);\n }\n reject(new Error(404, 'No records found with search and retrieve'));\n\n } catch (error) {\n reject(error);\n }\n })\n .on('error', error => {\n reject(error);\n });\n });\n}\n\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,uBAAuB;AAC9B,SAAQ,eAAe,SAAS,wBAAuB;AACvD,SAAQ,eAAc;AACtB,SAAQ,aAAY;AACpB,OAAO,WAAW;AAClB,SAAQ,WAAW,+BAA8B;AACjD,SAAQ,2BAA0B;AAIlC,MAAM,QAAQ,kBAAkB,uEAAuE;AAEvG,MAAM,WAAW,MAAM,OAAO,KAAK;AAEnC,MAAM,aAAa;AACnB,MAAM,UAAU;AAChB,MAAM,qBAAqB;AAC3B,MAAM,cAAc;AAIpB,0BAA2B;AACzB,QAAM,YAAY,gBAAgB,WAAW;AAE7C,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IAAU;AAAA,EACZ;AAEA,iBAAe,IAAI,QAAQ;AACzB,UAAM,aAAa,cAAc,MAAM;AAEvC,UAAM,iBAAiB,kBAAkB,OAAO,MAAM;AACtD,UAAM,UAAU,MAAM,QAAQ,YAAY,gBAAgB,IAAI;AAE9D,WAAO,EAAC,SAAS,KAAK,CAAC,GAAG,OAAO,KAAI;AAAA,EACvC;AAEA,iBAAe,SAAS,QAAQ;AAC9B,UAAM,aAAa,cAAc,MAAM;AAEvC,UAAM,iBAAiB,kBAAkB,OAAO,MAAM;AACtD,UAAM,UAAU,MAAM,QAAQ,YAAY,gBAAgB,KAAK;AAE/D,WAAO,EAAC,SAAS,OAAO,QAAQ,WAAW,EAAC;AAAA,EAC9C;AAGA,WAAS,sBAAsB,OAAO;AACpC,UAAM,YAAY,MAAM,WAAW,OAAO,QAAM,GAAG,SAAS,OAAO,GAAG,MAAM,MAAM,6CAA6C,CAAC;AAChI,WAAO;AAAA,EACT;AAEA,WAAS,gBAAgB,OAAO;AAC9B,QAAI,MAAM,QAAQ,OAAO;AACvB,aAAO;AAAA,IACT;AACA,WAAO,sBAAsB,KAAK,EAAE,SAAS;AAAA,EAC/C;AAEA,WAAS,kBAAkB,QAAQ;AACjC,WAAO,OAAO,OAAO,OAAK,gBAAgB,CAAC,CAAC;AAAA,EAC9C;AAEA,iBAAe,QAAQ,YAAY,QAAQ,WAAW,UAAU,CAAC,GAAG;AAElE,QAAI,eAAe,oBAAoB;AACrC,aAAO;AAAA,IACT;AACA,UAAM,CAAC,WAAW,GAAG,eAAe,IAAI;AAExC,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,sBAAsB,SAAS;AAE/C,UAAM,cAAc,MAAM,sBAAsB,SAAS,UAAU;AAEnE,QAAI,YAAY,WAAW,KAAK,YAAY,WAAW,QAAQ,QAAQ;AACrE,aAAO,QAAQ,YAAY,iBAAiB,WAAW,OAAO;AAAA,IAChE;AAEA,UAAM,mBAAmB,YAAY,IAAI,QAAM,iBAAiB,EAAE,CAAC;AACnE,YAAQ,+BAA+B,iBAAiB,KAAK,IAAI,CAAC,IAAI,QAAQ;AAG9E,QAAI,WAAW;AACb,gBAAU,YAAY,UAAU,UAAU,OAAO,QAAM,CAAC,iBAAiB,SAAS,iBAAiB,EAAE,CAAC,CAAC;AACvG,0BAAoB,SAAS;AAC7B,aAAO,QAAQ,YAAY,iBAAiB,WAAW,OAAO;AAAA,IAChE;AAEA,UAAM,cAAc,MAAM,SAAS;AACnC,UAAM,iBAAiB,cAAc,WAAW;AAChD,gBAAY,YAAY,YAAY,UAAU,OAAO,QAAM,CAAC,iBAAiB,SAAS,iBAAiB,EAAE,CAAC,CAAC;AAE3G,UAAM,aAAa,YAAY,cAAc,WAAW,cAAc,WAAW,CAAC;AAElF,WAAO,QAAQ,YAAY,iBAAiB,WAAW,CAAC,GAAG,SAAS,UAAU,CAAC;AAAA,EACjF;AAEA,iBAAe,sBAAsB,SAAS,YAAY,aAAa,CAAC,GAAG;AACzE,UAAM,CAAC,cAAc,GAAG,WAAW,IAAI;AAEvC,QAAI,CAAC,cAAc;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,MAAM,oBAAoB,cAAc,UAAU;AACvE,QAAI,cAAc;AAChB,aAAO,sBAAsB,aAAa,YAAY,CAAC,GAAG,YAAY,YAAY,CAAC;AAAA,IACrF;AACA,WAAO,sBAAsB,aAAa,YAAY,UAAU;AAAA,EAClE;AAEA,iBAAe,oBAAoB,UAAU,YAAY;AAEvD,UAAM,OAAO,SAAS,MAAM,UAAU,GAAG,CAAC;AAG1C,UAAM,cAAc,MAAM,cAAc,IAAI;AAI5C,QAAI,YAAY,KAAK,OAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG;AAClD,aAAO;AAAA,IACT;AACA,WAAO;AAEP,aAAS,oBAAoB,GAAG;AAC9B,YAAM,iBAAiB,cAAc,CAAC;AACtC,UAAI,mBAAmB,oBAAoB;AACzC,eAAO;AAAA,MACT;AACA,aAAO,mBAAmB;AAAA,IAC5B;AAAA,EACF;AAEA,iBAAe,cAAc,MAAM;AAEjC,UAAM,UAAU,MAAM,OAAO,WAAW,aAAa,IAAI,EAAE;AAE3D,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,QAAQ;AAC7B,UAAM,OAAO,OAAO,IAAI,KAAK;AAC7B,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,KAAK,CAAC,EAAE,UAAU,OAAO,QAAM,GAAG,SAAS,GAAG;AACxD,QAAI,EAAE,WAAW,GAAG;AAClB,aAAO;AAAA,IACT;AAEA,QAAI,EAAE,CAAC,EAAE,UAAU,KAAK;AACtB,aAAO;AAAA,IACT;AAEA,QAAI,EAAE,CAAC,EAAE,UAAU,KAAK;AACtB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAEF;AAIO,gBAAS,gBAAgB,WAAW;AAEzC,QAAM,mBAAmB;AAAA,IACvB,KAAK;AAAA,IACL,cAAc;AAAA,IACd,aAAa;AAAA,IACb,sBAAsB;AAAA,EACxB;AAEA,SAAO,wBAAwB,gBAAgB;AACjD;AAMO,gBAAS,OAAO,WAAW,OAAO,MAAM,OAAO;AAEpD,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,WAAW,CAAC;AAElB,UAAM,eAAe;AAAA,MACnB,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,gBAAgB;AAAA,IAClB;AAIA,cAAU,eAAe,KAAK,EAC3B,GAAG,UAAU,eAAa;AACzB,eAAS,KAAK,QAAQ,KAAK,WAAW,YAAY,CAAC;AAAA,IACrD,CAAC,EACA,GAAG,OAAO,YAAY;AACrB,UAAI;AAEF,YAAI,SAAS,SAAS,GAAG;AAEvB,cAAI,KAAK;AACP,kBAAM,CAAC,YAAY,IAAI;AACvB,kBAAM,cAAc,MAAM;AAC1B,mBAAO,QAAQ,WAAW;AAAA,UAC5B;AAEA,gBAAM,UAAU,MAAM,QAAQ,IAAI,QAAQ;AAC1C,iBAAO,QAAQ,OAAO;AAAA,QACxB;AACA,eAAO,IAAI,MAAM,KAAK,2CAA2C,CAAC;AAAA,MAEpE,SAAS,OAAO;AACd,eAAO,KAAK;AAAA,MACd;AAAA,IACF,CAAC,EACA,GAAG,SAAS,WAAS;AACpB,aAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACL,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/drop-terms.js
CHANGED
|
@@ -3,6 +3,7 @@ import createDebugLogger from "debug";
|
|
|
3
3
|
import { fieldToString, nvdebug } from "./utils.js";
|
|
4
4
|
import { getLexiconAndLanguage, getTermData, isLabel, isValidSubfield0 } from "./translate-terms.js";
|
|
5
5
|
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:drop-terms");
|
|
6
|
+
const debugDev = debug.extend("dev");
|
|
6
7
|
const defaultConfig = {
|
|
7
8
|
"constraints": [
|
|
8
9
|
{ "tag": "648", "lex": "yso/fin" },
|
|
@@ -99,19 +100,19 @@ export default function(config = defaultConfig) {
|
|
|
99
100
|
if (subfieldA) {
|
|
100
101
|
const lexData = getLexiconAndLanguage(field);
|
|
101
102
|
if (isLabel(data.prefLabel, subfieldA.value, lexData.lang)) {
|
|
102
|
-
|
|
103
|
+
nvdebug(`altLabel found: ${subfieldA.value}`, debugDev);
|
|
103
104
|
return false;
|
|
104
105
|
}
|
|
105
106
|
if (isLabel(data.altLabel, subfieldA.value, lexData.lang)) {
|
|
106
|
-
|
|
107
|
+
nvdebug(`altLabel found: ${subfieldA.value}`, debugDev);
|
|
107
108
|
return config["remove altLabel"];
|
|
108
109
|
}
|
|
109
|
-
|
|
110
|
+
nvdebug(`a-2-0 mismatch: ${fieldToString(field)}`, debugDev);
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
if (config["keep invalid label"]) {
|
|
113
114
|
if (!config["keep invalid url"]) {
|
|
114
|
-
nvdebug(`=============== 0-removal
|
|
115
|
+
nvdebug(`=============== 0-removal`, debugDev);
|
|
115
116
|
field.subfields = field.subfields.filter((sf) => sf.code !== "0");
|
|
116
117
|
}
|
|
117
118
|
return false;
|
package/dist/drop-terms.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/drop-terms.js"],
|
|
4
|
-
"sourcesContent": ["// Author(s): Nicholas Volk\n\nimport clone from 'clone';\nimport createDebugLogger from 'debug';\nimport {fieldToString, nvdebug} from './utils.js';\nimport {getLexiconAndLanguage, getTermData, isLabel, isValidSubfield0} from './translate-terms.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:drop-terms');\n
|
|
5
|
-
"mappings": "AAEA,OAAO,WAAW;AAClB,OAAO,uBAAuB;AAC9B,SAAQ,eAAe,eAAc;AACrC,SAAQ,uBAAuB,aAAa,SAAS,wBAAuB;AAE5E,MAAM,QAAQ,kBAAkB,qDAAqD;
|
|
4
|
+
"sourcesContent": ["// Author(s): Nicholas Volk\n\nimport clone from 'clone';\nimport createDebugLogger from 'debug';\nimport {fieldToString, nvdebug} from './utils.js';\nimport {getLexiconAndLanguage, getTermData, isLabel, isValidSubfield0} from './translate-terms.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:drop-terms');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst defaultConfig = {\n 'constraints': [\n {'tag': '648', 'lex': 'yso/fin'},\n {'tag': '648', 'lex': 'yso/swe'},\n {'tag': '650', 'lex': 'yso/fin'},\n {'tag': '650', 'lex': 'yso/swe'},\n {'tag': '651', 'lex': 'yso/fin'},\n {'tag': '651', 'lex': 'yso/swe'},\n {'tag': '655', 'lex': 'slm/fin'},\n {'tag': '655', 'lex': 'slm/swe'}\n ],\n 'keep invalid url': false, // If not true, removes illegal subfield $0. The whole field removal is later decided by 'keep 0-less'\n 'keep invalid label': false, // label ($a) is neither pref Label nor altLabel => remove whole field\n 'remove altLabel': false,\n 'remove 0-less': true\n};\n\n// eslint-disable-next-line max-lines-per-function\nexport default function (config = defaultConfig) {\n\n return {\n description: 'Drop yso and slm terms that do not match their identifiers. Use for incoming records only! Not for records already in Melinda!',\n validate, fix\n };\n\n async function fix(record, validateMode = false) {\n const clonedFields = record.fields.map(f => clone(f));\n\n const results = await processFields(clonedFields);\n\n const removables = results.map((f, i) => !f ? record.fields[i] : undefined).filter(f => f);\n const modMessages = results.map((f, i) => getMod(f, i)).filter(f => f);\n const removalMessages = removables.map(f => `Remove '${fieldToString(f)}'`);\n const allMessages = [...modMessages, ...removalMessages];\n\n if (validateMode) {\n if (allMessages.length === 0) {\n return {'message': [], 'valid': true};\n }\n return {'message': allMessages, 'valid': false};\n }\n\n removables.forEach(f => record.removeField(f));\n\n return {message: [], fix: allMessages, valid: true};\n\n function getMod(field, index) {\n if (!field) {\n return undefined;\n }\n const before = fieldToString(record.fields[index]);\n const after = fieldToString(results[index]);\n if (before !== after) {\n if (!validateMode) {\n record.fields[index] = field;\n }\n return `Modify '${before}' => '${after}'`;\n }\n return undefined;\n }\n }\n\n function isPotentialField(f) {\n if (!config || !config.constraints) {\n return false;\n }\n return config.constraints.some(c => c.tag === f.tag && f.subfields?.some(sf => sf.code === '2' && sf.value === c.lex));\n }\n\n async function validate(record) {\n return fix(record, true);\n }\n\n\n async function processFields(fields, results = []) {\n const [currField, ...remainingFields] = fields;\n if (!currField) {\n return results;\n }\n\n if (!isPotentialField(currField)) { // Not interested in this field\n return processFields(remainingFields, [...results, currField]);\n }\n\n removeSyntacticallyIllegalSubfield0s(currField); // iff config wants them to be removed...\n\n const removable = await isRemovableField(currField);\n\n return processFields(remainingFields, [...results, removable ? undefined : currField]);\n }\n\n function removeSyntacticallyIllegalSubfield0s(field) {\n if (config['keep invalid url']) {\n return;\n }\n\n const lexData = getLexiconAndLanguage(field);\n if (!lexData.lang) { // This is an error of sorts. Should we proceed and remove $0s?\n return;\n }\n\n field.subfields = field.subfields.filter(sf => sf.code !== '0' || isValidSubfield0(sf, lexData.lex));\n }\n\n async function isRemovableField(field) {\n // nvdebug(`FOO===== ${fieldToString(field)}`, debugDev);\n\n\n // $0-less field:\n if (!field.subfields.some(sf => sf.code === '0')) {\n return config['remove 0-less'];\n }\n\n const subfield0 = field.subfields.find(sf => sf.code === '0');\n const data = await getTermData(subfield0.value);\n // NB! No data might be a BUG! This might delete all incoming terms if Finto is down... (we should distinguish between a miss and a failure)\n // However, if we use this validator only for incoming records, it's fine enough.\n\n if (data) {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (subfieldA) {\n const lexData = getLexiconAndLanguage(field);\n\n // $a is the pref label. All is fine!\n if (isLabel(data.prefLabel, subfieldA.value, lexData.lang)) {\n nvdebug(`altLabel found: ${subfieldA.value}`, debugDev);\n return false;\n }\n if (isLabel(data.altLabel, subfieldA.value, lexData.lang)) {\n nvdebug(`altLabel found: ${subfieldA.value}`, debugDev);\n // Oddly enough this could remove altLabel but keep totally invalid labels...\n return config['remove altLabel'];\n }\n nvdebug(`a-2-0 mismatch: ${fieldToString(field)}`, debugDev);\n }\n }\n\n\n if (config['keep invalid label']) {\n // We keep the label $a. However, we can get rid of $0 if we want to (semantic reasons)\n if (!config['keep invalid url']) {\n nvdebug(`=============== 0-removal`, debugDev);\n field.subfields = field.subfields.filter(sf => sf.code !== '0');\n }\n return false;\n }\n return true;\n\n }\n\n\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/fix-33X.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import createDebugLogger from "debug";
|
|
1
2
|
import clone from "clone";
|
|
2
3
|
import { fieldToString, getCatalogingLanguage, nvdebug } from "./utils.js";
|
|
3
4
|
import { map336CodeToTerm, map337CodeToTerm, map338CodeToTerm } from "./field33XUtils.js";
|
|
5
|
+
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:fix-33X");
|
|
6
|
+
const debugDev = debug.extend("dev");
|
|
4
7
|
const description = "Fix non-RDA 33X field(s)";
|
|
5
8
|
const map336 = {
|
|
6
9
|
"Bild (kartografisk ; att vidra)": "crt",
|
|
@@ -369,16 +372,16 @@ export default function() {
|
|
|
369
372
|
fix
|
|
370
373
|
};
|
|
371
374
|
function fix(record) {
|
|
372
|
-
nvdebug(`FIX ${description}
|
|
375
|
+
nvdebug(`FIX ${description}...`, debugDev);
|
|
373
376
|
const catLang = getCatalogingLanguage(record) || "fin";
|
|
374
377
|
const fields = getRelevantFields(record);
|
|
375
378
|
fields.forEach((f) => fixField(f, catLang));
|
|
376
|
-
nvdebug(` GOT ${fields.length}
|
|
379
|
+
nvdebug(` GOT ${fields.length}...`, debugDev);
|
|
377
380
|
const res = { message: [], fix: [], valid: true };
|
|
378
381
|
return res;
|
|
379
382
|
}
|
|
380
383
|
function validate(record) {
|
|
381
|
-
nvdebug(`VALIDATE ${description}
|
|
384
|
+
nvdebug(`VALIDATE ${description}...`, debugDev);
|
|
382
385
|
const catLang = getCatalogingLanguage(record) || "fin";
|
|
383
386
|
const fields = getRelevantFields(record);
|
|
384
387
|
if (fields.length === 0) {
|
|
@@ -399,7 +402,7 @@ export default function() {
|
|
|
399
402
|
return void 0;
|
|
400
403
|
}
|
|
401
404
|
function mapTermToCode(term, tag) {
|
|
402
|
-
nvdebug(`TERM/${tag}: '${term}'
|
|
405
|
+
nvdebug(`TERM/${tag}: '${term}'`, debugDev);
|
|
403
406
|
if (tag === "336" && term in map336) {
|
|
404
407
|
return map336[term];
|
|
405
408
|
}
|