@natlibfi/marc-record-validators-melinda 12.0.6 → 12.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cyrillux.js +11 -11
- package/dist/cyrillux.js.map +2 -2
- package/dist/dataProvenanceUtils.js +19 -0
- package/dist/dataProvenanceUtils.js.map +7 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +2 -2
- package/dist/merge-fields/controlSubfields.js.map +2 -2
- package/dist/merge-fields/counterpartField.js +149 -152
- package/dist/merge-fields/counterpartField.js.map +3 -3
- package/dist/merge-fields/dataProvenance.js +6 -20
- package/dist/merge-fields/dataProvenance.js.map +2 -2
- package/dist/merge-fields/index.js +1 -1
- package/dist/merge-fields/index.js.map +2 -2
- package/dist/merge-fields/mergableIndicator.js +1 -2
- package/dist/merge-fields/mergableIndicator.js.map +2 -2
- package/dist/merge-fields/mergeConfig.js +2 -0
- package/dist/merge-fields/mergeConfig.js.map +2 -2
- package/dist/merge-fields/mergeConstraints.js +35 -32
- package/dist/merge-fields/mergeConstraints.js.map +3 -3
- package/dist/merge-fields/mergeField.js +4 -3
- package/dist/merge-fields/mergeField.js.map +2 -2
- package/dist/merge-fields/mergeOrAddSubfield.js +8 -7
- package/dist/merge-fields/mergeOrAddSubfield.js.map +2 -2
- package/dist/merge-fields/mergeSubfield.js +5 -1
- package/dist/merge-fields/mergeSubfield.js.map +2 -2
- package/dist/merge-fields/worldKnowledge.js +52 -0
- package/dist/merge-fields/worldKnowledge.js.map +2 -2
- package/dist/merge-fields.test.js +2 -2
- package/dist/merge-fields.test.js.map +2 -2
- package/dist/normalize-dashes.js +2 -2
- package/dist/normalize-dashes.js.map +2 -2
- package/dist/normalizeFieldForComparison.js +8 -14
- package/dist/normalizeFieldForComparison.js.map +2 -2
- package/dist/prepublicationUtils.js +1 -1
- package/dist/prepublicationUtils.js.map +2 -2
- package/dist/punctuation2.js +10 -10
- package/dist/punctuation2.js.map +2 -2
- package/dist/removeDuplicateDataFields.js +1 -24
- package/dist/removeDuplicateDataFields.js.map +2 -2
- package/dist/removeInferiorDataFields.js +3 -2
- package/dist/removeInferiorDataFields.js.map +2 -2
- package/dist/sortSubfields.js +19 -19
- package/dist/sortSubfields.js.map +2 -2
- package/dist/subfield6Utils.js +0 -1
- package/dist/subfield6Utils.js.map +2 -2
- package/dist/subfield8Utils.js +0 -5
- package/dist/subfield8Utils.js.map +2 -2
- package/dist/utils.js +29 -3
- package/dist/utils.js.map +2 -2
- package/package.json +4 -4
- package/src/cyrillux.js +11 -11
- package/src/dataProvenanceUtils.js +21 -0
- package/src/index.js +3 -1
- package/src/merge-fields/controlSubfields.js +0 -1
- package/src/merge-fields/counterpartField.js +191 -290
- package/src/merge-fields/dataProvenance.js +8 -25
- package/src/merge-fields/index.js +1 -1
- package/src/merge-fields/mergableIndicator.js +1 -2
- package/src/merge-fields/mergeConfig.js +2 -1
- package/src/merge-fields/mergeConstraints.js +39 -34
- package/src/merge-fields/mergeField.js +4 -7
- package/src/merge-fields/mergeOrAddSubfield.js +8 -7
- package/src/merge-fields/mergeSubfield.js +11 -2
- package/src/merge-fields/worldKnowledge.js +72 -3
- package/src/merge-fields.test.js +2 -2
- package/src/normalize-dashes.js +2 -2
- package/src/normalizeFieldForComparison.js +19 -20
- package/src/prepublicationUtils.js +1 -1
- package/src/punctuation2.js +10 -10
- package/src/removeDuplicateDataFields.js +24 -24
- package/src/removeInferiorDataFields.js +3 -2
- package/src/sortSubfields.js +19 -19
- package/src/subfield6Utils.js +1 -1
- package/src/subfield8Utils.js +5 -5
- package/src/utils.js +39 -12
- package/test-fixtures/cyrillux/f14/expectedResult.json +32 -0
- package/test-fixtures/cyrillux/f14/metadata.json +10 -0
- package/test-fixtures/cyrillux/f14/record.json +14 -0
- package/test-fixtures/merge-fields/f042_01/expectedResult.json +12 -0
- package/test-fixtures/merge-fields/f042_01/metadata.json +6 -0
- package/test-fixtures/merge-fields/f042_01/record.json +13 -0
- package/test-fixtures/merge-fields/f06/expectedResult.json +42 -0
- package/test-fixtures/merge-fields/f06/metadata.json +6 -0
- package/test-fixtures/merge-fields/f06/record.json +41 -0
- package/test-fixtures/merge-fields/f07/expectedResult.json +18 -0
- package/test-fixtures/merge-fields/f07/metadata.json +6 -0
- package/test-fixtures/merge-fields/f07/record.json +18 -0
- package/test-fixtures/merge-fields/f08/expectedResult.json +12 -0
- package/test-fixtures/merge-fields/f08/metadata.json +7 -0
- package/test-fixtures/merge-fields/f08/record.json +10 -0
- package/test-fixtures/merge-fields/f09/expectedResult.json +14 -0
- package/test-fixtures/merge-fields/f09/metadata.json +6 -0
- package/test-fixtures/merge-fields/f09/record.json +14 -0
- package/test-fixtures/merge-fields/f10/expectedResult.json +25 -0
- package/test-fixtures/merge-fields/f10/metadata.json +6 -0
- package/test-fixtures/merge-fields/f10/record.json +25 -0
- package/test-fixtures/merge-fields/f11/expectedResult.json +40 -0
- package/test-fixtures/merge-fields/f11/metadata.json +7 -0
- package/test-fixtures/merge-fields/f11/record.json +50 -0
- package/test-fixtures/merge-fields/f12/expectedResult.json +17 -0
- package/test-fixtures/merge-fields/f12/metadata.json +6 -0
- package/test-fixtures/merge-fields/f12/record.json +25 -0
- package/test-fixtures/merge-fields/f13/expectedResult.json +18 -0
- package/test-fixtures/merge-fields/f13/metadata.json +6 -0
- package/test-fixtures/merge-fields/f13/record.json +28 -0
- package/test-fixtures/merge-fields/f14/expectedResult.json +25 -0
- package/test-fixtures/merge-fields/f14/metadata.json +6 -0
- package/test-fixtures/merge-fields/f14/record.json +25 -0
- package/test-fixtures/merge-fields/f300_01/expectedResult.json +9 -0
- package/test-fixtures/merge-fields/f300_01/metadata.json +6 -0
- package/test-fixtures/merge-fields/f300_01/record.json +8 -0
- package/test-fixtures/merge-fields/f300_02/expectedResult.json +13 -0
- package/test-fixtures/merge-fields/f300_02/metadata.json +6 -0
- package/test-fixtures/merge-fields/f300_02/record.json +16 -0
- package/test-fixtures/merge-fields/f490_01/expectedResult.json +13 -0
- package/test-fixtures/merge-fields/f490_01/metadata.json +6 -0
- package/test-fixtures/merge-fields/f490_01/record.json +16 -0
- package/test-fixtures/remove-inferior-datafields/f17/expectedResult.json +11 -0
- package/test-fixtures/remove-inferior-datafields/f17/metadata.json +5 -0
- package/test-fixtures/remove-inferior-datafields/f17/record.json +15 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/removeInferiorDataFields.js"],
|
|
4
|
-
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport {fieldToChain, sameField} from './removeDuplicateDataFields.js';\nimport {fieldGetOccurrenceNumberPairs, fieldHasValidSubfield6, fieldSevenToOneOccurrenceNumber, fieldsToNormalizedString} from './subfield6Utils.js';\nimport {fieldHasSubfield, fieldsToString, fieldToString, /*nvdebug,*/ uniqArray} from './utils.js';\nimport {fieldHasValidSubfield8} from './subfield8Utils.js';\nimport {encodingLevelIsBetterThanPrepublication, fieldRefersToKoneellisestiTuotettuTietue, getEncodingLevel} from './prepublicationUtils.js';\nimport {cloneAndNormalizeFieldForComparison} from './normalizeFieldForComparison.js';\nimport {fixComposition, precomposeFinnishLetters} from './normalize-utf8-diacritics.js';\n\n// Relocated from melinda-marc-record-merge-reducers (and renamed)\n\n// NB! This validator handles only full fields, and does not support subfield $8 removal.\n// Also, having multiple $8 subfields in same fields is not supported.\n// If this functionality is needed, see removeDuplicateDatafields.js for examples of subfield-only stuff.\n// const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:removeInferiorDataFields');\n\nexport default function () {\n return {\n description: 'Remove subset data fields. Certain exceptions apply, mainly too complicated for chained fields',\n validate, fix\n };\n\n function fix(record) {\n //nvdebug('Fix record: remove inferior (eg. subset) data fields', debug);\n const res = {message: [], fix: [], valid: true};\n removeInferiorDatafields(record, true);\n // This can not really fail...\n return res;\n }\n\n function validate(record) {\n // Check max, and check number of different indexes\n //nvdebug('Validate record: remove inferior (eg. subset) data fields', debug);\n\n const duplicates = removeInferiorDatafields(record, false);\n\n const res = {message: duplicates};\n\n res.valid = res.message.length < 1;\n return res;\n }\n}\n\n\nfunction deriveInferiorChains(fields, record) {\n //nvdebug(`======= GOT ${fields.length} FIELDS TO CHAINIFY`);\n const hash = {};\n\n fields.forEach(f => fieldToChainToDeletables(f));\n\n return hash;\n\n //nvdebug(`WP1: GOT ${todoList.length} CHAINS`);\n\n\n // here we map deletableStringObject[str] => field. The idea is to help debugging. We don't actually need the field object...\n //return deriveChainDeletables(todoList);\n\n function fieldToChainToDeletables(field) {\n const chain = fieldToChain(field, record);\n if (chain.length < 2) {\n return;\n }\n const chainAsString = fieldsToNormalizedString(chain, 0, true, true);\n const arr = deriveChainDeletables([chainAsString]);\n //nvdebug(`GOT ${arr.length} DELETABLES FOR ${chainAsString}`);\n arr.forEach(val => {\n if (!(val in hash)) {\n hash[val] = field;\n }\n });\n }\n\n function deriveChainDeletables(todoList, deletables = []) {\n const [chainAsString, ...stillToDo] = todoList;\n if (chainAsString === undefined) {\n return deletables;\n }\n\n // Fix MRA-476 (part 1): one $6 value can be worse than the other\n const withoutScriptIdentificationCode = chainAsString.replace(/( \u20216 [0-9X][0-9][0-9]-(?:XX|[0-9]+))\\/[^ ]+/u, '$1');\n\n // Remove keepless versions:\n const keepless = chainAsString.replace(/ \u20219 [A-Z]+<KEEP>/u, '');\n\n // MRA-433: 490 ind1=1 vs ind1=0: remove latter (luckily no 2nd indicator etc)\n const linked490Ind1 = chainAsString.replace(/^490 1/u, '490 0').replace(/\\t880 1/ug, '\\t880 0');\n const arr = [withoutScriptIdentificationCode, keepless, linked490Ind1].filter(val => val !== chainAsString);\n if (arr.length > 0) {\n return deriveChainDeletables([...stillToDo, ...arr], [...deletables, ...arr]);\n }\n\n return deriveChainDeletables(stillToDo, deletables);\n }\n\n}\n\nfunction isRelevantChain6(field, record) {\n //Can't be a chain:\n if (!fieldHasValidSubfield6(field) && !fieldHasValidSubfield8(field)) {\n return false;\n }\n // Too short to be a chain:\n const chain = fieldToChain(field, record);\n if (chain.length < 2) {\n return false;\n }\n // No field can contains no more than one subfield $6\n if (chain.some(f => f.subfields.filter(sf => sf.code === '6').length > 1)) {\n return false;\n }\n\n // Check whether our field is the head of a chain:\n return sameField(field, chain[0]);\n}\n\nexport function removeInferiorChains(record, fix = true) {\n const fields = record.fields.filter(f => isRelevantChain6(f, record));\n //nvdebug(`WP2.0: GOT ${fields.length} chain(s)`);\n\n const deletableChainsAsKeys = deriveInferiorChains(fields, record);\n const nChains = Object.keys(deletableChainsAsKeys).length;\n //nvdebug(`WP2: GOT ${nChains} chain(s)`);\n if (nChains === 0) {\n return [];\n }\n\n //nvdebug(`removeInferiorChains() has ${fields.length} fields-in-chain(s), and a list of ${nChains} deletable(s)`);\n\n return innerRemoveInferiorChains(fields);\n\n function innerRemoveInferiorChains(fields, deletedStringsArray = []) {\n const [currField, ...remainingFields] = fields;\n\n if (currField === undefined) {\n return deletedStringsArray;\n }\n\n const chain = fieldToChain(currField, record);\n if (chain.length === 0 || !sameField(currField, chain[0])) {\n return innerRemoveInferiorChains(remainingFields, deletedStringsArray);\n }\n\n const chainAsString = fieldsToNormalizedString(chain, 0, true, true);\n if (!(chainAsString in deletableChainsAsKeys)) {\n return innerRemoveInferiorChains(remainingFields, deletedStringsArray);\n }\n\n const triggeringField = deletableChainsAsKeys[chainAsString];\n const triggeringChain = fieldToChain(triggeringField, record);\n\n // If the inferior (deletable) chain is 1XX-based, convert the triggering better chain from 7XX to 1XX:\n if (chainContains1XX(chain)) {\n triggeringChain.forEach(f => sevenToOne(f, triggeringChain));\n }\n //nvdebug(`iRIS6C: ${chainAsString}`);\n const deletedString = fieldsToString(chain);\n const message = `DEL: '${deletedString}' REASON: '${fieldsToString(triggeringChain)}'`;\n if (fix) {\n //nvdebug(`INFERIOR $6 CHAIN REMOVAL: ${message}}`, debug);\n chain.forEach(field => record.removeField(field));\n }\n return innerRemoveInferiorChains(remainingFields, [...deletedStringsArray, message]);\n }\n\n function chainContains1XX(chain) {\n return chain.some(f => f.tag.substring(0, 1) === '1');\n }\n\n function sevenToOne(field, chain) { // Change 7XX field to 1XX field. Also handle the corresponding 880$6 7XX-NN subfields\n // NB! This function should be called only if the original 1XX gets deleted!\n if (!['700', '710', '711', '730'].includes(field.tag)) {\n return;\n }\n // Retag field 7XX as 1XX and fix corresponding occurrence numbers as well:\n const pairs = fieldGetOccurrenceNumberPairs(field, chain);\n field.tag = `1${field.tag.substring(1)}`;\n // There should always be one pair, but I'm not sanity-checking this\n pairs.forEach(pairedField => fieldSevenToOneOccurrenceNumber(pairedField));\n }\n\n}\n\n\nfunction getIdentifierlessAndKeeplessSubsets(fieldAsString) {\n // The rules below are not perfect (in complex cases they don't catch all permutations), but good enough:\n // Remove identifier(s) (MELKEHITYS-2383-ish):\n\n const identifierlessString = fieldAsString.replace(/ \u2021[01] [^\u2021]+($| \u2021)/u, '$1');\n const keeplessString = fieldAsString.replace(/ \u20219 [A-Z]+<KEEP>/u, '');\n\n return [identifierlessString, keeplessString].filter(val => val !== fieldAsString);\n}\n\nfunction deriveIndividualDeletables490(todoList, deletables = []) {\n const [fieldAsString, ...stillToDo] = todoList;\n if (fieldAsString === undefined) {\n return deletables;\n }\n //nvdebug(`PROCESS ${fieldAsString}`);\n if (!fieldAsString.match(/^490/u)) {\n return deriveIndividualDeletables490(stillToDo, deletables);\n }\n\n // $6-less version (keep this first)\n const sixless = fieldAsString.replace(/ \u20216 [^\u2021]+ \u2021/u, ' \u2021');\n\n // Without final $v or $x:\n const withoutFinalVOrX = fieldAsString.replace(/ *[;,] \u2021[vx] [^\u2021]+$/u, '');\n // Add intermediate $x-less version\n const xless = fieldAsString.replace(/, \u2021x [^\u2021]+(, \u2021x| ; \u2021v)/u, '$1');\n\n // Add $xv-less version (handled by recursion?)\n const xvless = fieldAsString.replace(/, \u2021x [^\u2021]+ \u2021v [^\u2021]+$/u, '');\n\n // MRA-433-ish (non-chain): 490 ind1=1 vs ind1=0: remove latter\n const modifiedInd2 = fieldAsString.match(/^490 1/u) ? `490 0${fieldAsString.substring(5)}` : fieldAsString;\n\n const arr = [sixless, withoutFinalVOrX, xless, xvless, modifiedInd2].filter(val => val !== fieldAsString);\n\n /*\n if (arr.length) {\n nvdebug(`${arr.length} derivation(s) for ${fieldAsString}`);\n nvdebug(arr.join('\\n'));\n }\n */\n return arr;\n}\n\nfunction deriveIndividualDeletables(record) {\n const todoList = record.fields.map(f => fieldToString(f));\n //const finishedRecord = encodingLevelIsBetterThanPrepublication(getEncodingLevel(record));\n\n const deletableStringsArray = processTodoList(todoList);\n\n const inferiorTerms = getInferiorTerms(record);\n\n return uniqArray([...deletableStringsArray, ...inferiorTerms]);\n\n function getInferiorTerms(record) {\n const inputFields = record.fields.filter(f => ['648', '650', '651'].includes(f.tag) && f.subfields);\n const result = inputFields.flatMap(f => fieldToInferiorFields(f));\n\n // console.log(result.join('\\n')); // eslint-disable-line no-console\n return result;\n }\n\n function fieldToInferiorFields(field) {\n const aArray = field.subfields.filter(sf => sf.code === 'a');\n if (field.tag === '650') {\n return aArray.flatMap(sf => [`653 ## \u2021a ${sf.value}`, `653 #0 \u2021a ${sf.value}`]);\n }\n return aArray.map(sf => `653 ## \u2021a ${sf.value}`);\n }\n\n function processTodoList(thingsToDo, deletables = []) {\n const [currString, ...stillToDo] = thingsToDo;\n\n if (currString === undefined) {\n return deletables;\n }\n\n const accentless = getAccentlessVersion(currString);\n const d490 = deriveIndividualDeletables490([currString]);\n const subsets = getIdentifierlessAndKeeplessSubsets(currString);\n const moreToDo = [...accentless, ...d490, ...subsets];\n\n\n if (currString.match(/^[1678]00/u)) {\n // Proof-of-concept rule. Should be improved eventually...\n if (currString.match(/, \u2021e [^\u2021]+\\.$/u)) {\n const tmp = currString.replace(/, \u2021e [^\u2021]+\\.$/u, '.');\n return processTodoList([tmp, ...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n }\n\n if (currString.match(/^500 ## \u2021a Lis\u00E4painokset: Lis\u00E4painos /u)) { // MET-569\n const tmp1 = currString.replace(' Lis\u00E4painos ', ' [Lis\u00E4painos] ');\n const tmp2 = currString.replace(' Lis\u00E4painos ', ' ');\n if (tmp1 !== currString && tmp2 !== currString) {\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp1, tmp2]);\n }\n }\n\n if (currString.match(/^500 ## \u2021a Lis\u00E4painokset: \\[Lis\u00E4painos\\] /u)) { // MET-569\n const tmp = currString.replace(' [Lis\u00E4painos] ', ' ');\n if (tmp !== currString) {\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n }\n\n if (currString.match(/^500 ## \u2021a Ei vastaanotettu\\.$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '500 ## \u2021a EI VASTAANOTETTU.']);\n }\n if (currString.match(/^500 ## \u2021a Ei ilmesty\\.$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '500 ## \u2021a EI ILMESTY.']);\n }\n\n if (currString.match(/^505 .0.*-- \u2021t/u)) { // MRA-413-ish\n const tmp = currString.replace(/ -- \u2021t /gu, ' -- '). // remove non-initial $t subfields\n replace(/ \u2021[rg] /gu, ' '). // remove $r and $g subfields\n replace(/ \u2021t /u, ' \u2021a '). // change first $t to $a\n // ind2: '1' => '#':\n replace(/^505 (.)0/u, '505 $1#');\n if (tmp !== currString) {\n return processTodoList([tmp, ...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n //nvdebug(`505 ORIGINAL: '${fieldAsString}'`)\n //nvdebug(`505 DERIVATE: '${tmp}'`)\n }\n\n if (currString.match(/^594 ## \u2021a Ei vastaanotettu \u20215 FENNI$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '594 ## \u2021a EI VASTAANOTETTU \u20215 FENNI']);\n }\n if (currString.match(/^594 ## \u2021a Ei ilmesty \u20215 FENNI$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '594 ## \u2021a EI ILMESTY \u20215 FENNI']);\n }\n\n // MET-381: remove occurence number TAG-00, if TAG-NN existists\n if (currString.match(/^880.* \u20216 [0-9][0-9][0-9]-(?:[1-9][0-9]|0[1-9])/u)) {\n const tmp = currString.replace(/( \u20216 [0-9][0-9][0-9])-[0-9]+/u, '$1-00');\n //nvdebug(`MET-381: ADD TO DELETABLES: '${tmp}'`);\n //deletableStringsArray.push(tmp);\n if (tmp.match(/ \u20216 [0-9][0-9][0-9]-00\\/[^ ]+ /u)) {\n const tmp2 = tmp.replace(/( \u20216 [0-9][0-9][0-9]-00)[^ ]+/u, '$1');\n //nvdebug(`MET-381: ADD TO DELETABLES: '${tmp2}'`);\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp, tmp2]);\n }\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n\n // MET-575 (merge: applies in postprocessing)\n const inferiorTerms = getPrepublicationTerms(currString);\n\n // MELKEHITYS-3277-ish: non-AI is better than AI (a rare case where longer version is inferior):\n const aiBased = `${currString} \u20217 (dpenmw)AI`;\n\n const newDeletables = [...deletables, ...subsets, ...accentless, ...d490, ...inferiorTerms, aiBased];\n\n if (subsets.length) {\n return processTodoList([...stillToDo, ...moreToDo], newDeletables);\n }\n\n return processTodoList([...stillToDo, ...moreToDo], newDeletables);\n }\n\n function getAccentlessVersion(string) { // MET-527\n //nvdebug(`START: '${string}`);\n // This is a sanity check: if precomposition does something, there's something wrong, and we don't want to proceed..\n if (string !== precomposeFinnishLetters(string)) {\n return [];\n }\n const accentless = String(fixComposition(string)).replace(/\\p{Diacritic}/gu, '');\n //nvdebug(`FROM '${string}'\\n TO '${accentless}'`);\n if (accentless === string) { // Don't self-destruct\n return [];\n }\n return [accentless];\n }\n\n function getPrepublicationTerms(fieldAsString) {\n if (fieldAsString.match(/^653./u)) {\n // MET-528 (extented by MET-575)\n return [`${fieldAsString} \u2021g ENNAKKOTIETO`, `${fieldAsString} \u2021g Ennakkotieto`, `${fieldAsString} \u2021g ennakkotieto`, `${fieldAsString} \u2021g ENNAKKOTIETO.`, `${fieldAsString} \u2021g Ennakkotieto.`, `${fieldAsString} \u2021g ennakkotieto.`];\n }\n\n return [];\n }\n\n}\n\nfunction fieldToNormalizedString(field) {\n const normalizedField = cloneAndNormalizeFieldForComparison(field);\n return fieldToString(normalizedField);\n}\n\nfunction deriveIndividualNormalizedDeletables(record) { // MET-461:\n const encodingLevel = getEncodingLevel(record);\n const recordIsFinished = encodingLevelIsBetterThanPrepublication(encodingLevel);\n const met495 = encodingLevel === '2' && record.fields.some(f => f.tag === '500' && fieldRefersToKoneellisestiTuotettuTietue(f));\n if (!recordIsFinished || met495) {\n return [];\n }\n const relevantFields = record.fields.filter(f => ['245', '246'].includes(f.tag) && fieldHasSubfield(f, 'a'));\n\n return deriveDeletable946s(relevantFields);\n\n function deriveDeletable946s(fields, results = []) {\n const [currField, ...remainingFields] = fields;\n if (currField === undefined) {\n return results;\n }\n\n const fieldAsNormalizedString = fieldToNormalizedString(currField);\n const tmp = fieldAsNormalizedString.replace(/^(?:...) ../u, '946 ##'). // <= Change tag to 946 and indicators to '##'\n replace(' \u2021a ', ' \u2021i nimeke onixissa \u2021a '). // Add $i before $a. NB! This is added in the normalized lower-cased form!\n replace(/(?: \\/)? \u2021c[^\u2021]+$/u, ''); // Remove $c. (Can $c be non-last?)\n const candArray = [tmp, `${tmp} \u20215 MELINDA`].filter(val => val !== fieldAsNormalizedString);\n if (candArray.length) {\n return deriveDeletable946s(remainingFields, [...results, ...candArray]);\n }\n return deriveDeletable946s(remainingFields, results);\n }\n}\n\nexport function removeIndividualInferiorDatafields(record, fix = true) { // No $6 nor $8 in field\n const deletableFieldsAsStrings = deriveIndividualDeletables(record);\n const deletableFieldsAsNormalizedStrings = deriveIndividualNormalizedDeletables(record);\n\n // nvdebug(`Deletables:\\n ${deletableFieldsAsStrings.join('\\n ')}`);\n // nvdebug(`Normalized deletables:\\n ${deletableFieldsAsNormalizedStrings.join('\\n ')}`);\n\n const hits = record.fields.filter(field => isDeletableField(field));\n\n const deletedFieldsAsStrings = hits.map(f => fieldToString(f));\n\n if (fix) {\n hits.forEach(field => {\n //nvdebug(`Remove inferior field: ${fieldToString(field)}`, debug);\n record.removeField(field);\n });\n }\n\n return deletedFieldsAsStrings;\n\n function isDeletableField(field) {\n const fieldAsString = fieldToString(field);\n if (deletableFieldsAsStrings.includes(fieldAsString)) {\n return true;\n }\n const fieldAsNormalizedString = fieldToNormalizedString(field);\n if (deletableFieldsAsNormalizedStrings.includes(fieldAsNormalizedString)) {\n return true;\n }\n\n return false;\n }\n}\n\n\nexport function removeInferiorDatafields(record, fix = true) {\n const removables = removeIndividualInferiorDatafields(record, fix); // Lone fields\n //const removables8 = removeDuplicateSubfield8Chains(record, fix); // Lone subfield $8 chains\n const removables6 = removeInferiorChains(record, fix); // Lone subfield $6 chains\n // HOW TO HANDLE $6+$8 combos? Skipping is relatively OK.\n\n //nvdebug(`REMOVABLES:\\n ${removables.join('\\n ')}`, debug);\n //nvdebug(`REMOVABLES 6:\\n ${removables6.join('\\n ')}`, debug);\n\n const removablesAll = removables.concat(removables6); //.concat(removables8);\n\n return removablesAll;\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["//import createDebugLogger from 'debug';\nimport {fieldToChain, sameField} from './removeDuplicateDataFields.js';\nimport {fieldGetOccurrenceNumberPairs, fieldHasValidSubfield6, fieldSevenToOneOccurrenceNumber, fieldsToNormalizedString} from './subfield6Utils.js';\nimport {fieldHasSubfield, fieldsToString, fieldToString, /*nvdebug,*/ uniqArray} from './utils.js';\nimport {fieldHasValidSubfield8} from './subfield8Utils.js';\nimport {encodingLevelIsBetterThanPrepublication, fieldRefersToKoneellisestiTuotettuTietue, getEncodingLevel} from './prepublicationUtils.js';\nimport {cloneAndNormalizeFieldForComparison} from './normalizeFieldForComparison.js';\nimport {fixComposition, precomposeFinnishLetters} from './normalize-utf8-diacritics.js';\n\n// Relocated from melinda-marc-record-merge-reducers (and renamed)\n\n// NB! This validator handles only full fields, and does not support subfield $8 removal.\n// Also, having multiple $8 subfields in same fields is not supported.\n// If this functionality is needed, see removeDuplicateDatafields.js for examples of subfield-only stuff.\n// const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:removeInferiorDataFields');\n\nexport default function () {\n return {\n description: 'Remove subset data fields. Certain exceptions apply, mainly too complicated for chained fields',\n validate, fix\n };\n\n function fix(record) {\n //nvdebug('Fix record: remove inferior (eg. subset) data fields', debug);\n const res = {message: [], fix: [], valid: true};\n removeInferiorDatafields(record, true);\n // This can not really fail...\n return res;\n }\n\n function validate(record) {\n // Check max, and check number of different indexes\n //nvdebug('Validate record: remove inferior (eg. subset) data fields', debug);\n\n const duplicates = removeInferiorDatafields(record, false);\n\n const res = {message: duplicates};\n\n res.valid = res.message.length < 1;\n return res;\n }\n}\n\n\nfunction deriveInferiorChains(fields, record) {\n //nvdebug(`======= GOT ${fields.length} FIELDS TO CHAINIFY`);\n const hash = {};\n\n fields.forEach(f => fieldToChainToDeletables(f));\n\n return hash;\n\n //nvdebug(`WP1: GOT ${todoList.length} CHAINS`);\n\n\n // here we map deletableStringObject[str] => field. The idea is to help debugging. We don't actually need the field object...\n //return deriveChainDeletables(todoList);\n\n function fieldToChainToDeletables(field) {\n const chain = fieldToChain(field, record);\n if (chain.length < 2) {\n return;\n }\n const chainAsString = fieldsToNormalizedString(chain, 0, true, true);\n const arr = deriveChainDeletables([chainAsString]);\n //nvdebug(`GOT ${arr.length} DELETABLES FOR ${chainAsString}`);\n arr.forEach(val => {\n if (!(val in hash)) {\n hash[val] = field;\n }\n });\n }\n\n function deriveChainDeletables(todoList, deletables = []) {\n const [chainAsString, ...stillToDo] = todoList;\n if (chainAsString === undefined) {\n return deletables;\n }\n\n // Fix MRA-476 (part 1): one $6 value can be worse than the other\n const withoutScriptIdentificationCode = chainAsString.replace(/( \u20216 [0-9X][0-9][0-9]-(?:XX|[0-9]+))\\/[^ ]+/u, '$1');\n\n // Remove keepless versions:\n const keepless = chainAsString.replace(/ \u20219 [A-Z]+<KEEP>/u, '');\n\n // MRA-433: 490 ind1=1 vs ind1=0: remove latter (luckily no 2nd indicator etc)\n const linked490Ind1 = chainAsString.replace(/^490 1/u, '490 0').replace(/\\t880 1/ug, '\\t880 0');\n const arr = [withoutScriptIdentificationCode, keepless, linked490Ind1].filter(val => val !== chainAsString);\n if (arr.length > 0) {\n return deriveChainDeletables([...stillToDo, ...arr], [...deletables, ...arr]);\n }\n\n return deriveChainDeletables(stillToDo, deletables);\n }\n\n}\n\nfunction isRelevantChain6(field, record) {\n //Can't be a chain:\n if (!fieldHasValidSubfield6(field) && !fieldHasValidSubfield8(field)) {\n return false;\n }\n // Too short to be a chain:\n const chain = fieldToChain(field, record);\n if (chain.length < 2) {\n return false;\n }\n // No field can contains no more than one subfield $6\n if (chain.some(f => f.subfields.filter(sf => sf.code === '6').length > 1)) {\n return false;\n }\n\n // Check whether our field is the head of a chain:\n return sameField(field, chain[0]);\n}\n\nexport function removeInferiorChains(record, fix = true) {\n const fields = record.fields.filter(f => isRelevantChain6(f, record));\n //nvdebug(`WP2.0: GOT ${fields.length} chain(s)`);\n\n const deletableChainsAsKeys = deriveInferiorChains(fields, record);\n const nChains = Object.keys(deletableChainsAsKeys).length;\n //nvdebug(`WP2: GOT ${nChains} chain(s)`);\n if (nChains === 0) {\n return [];\n }\n\n //nvdebug(`removeInferiorChains() has ${fields.length} fields-in-chain(s), and a list of ${nChains} deletable(s)`);\n\n return innerRemoveInferiorChains(fields);\n\n function innerRemoveInferiorChains(fields, deletedStringsArray = []) {\n const [currField, ...remainingFields] = fields;\n\n if (currField === undefined) {\n return deletedStringsArray;\n }\n\n const chain = fieldToChain(currField, record);\n if (chain.length === 0 || !sameField(currField, chain[0])) {\n return innerRemoveInferiorChains(remainingFields, deletedStringsArray);\n }\n\n const chainAsString = fieldsToNormalizedString(chain, 0, true, true);\n if (!(chainAsString in deletableChainsAsKeys)) {\n return innerRemoveInferiorChains(remainingFields, deletedStringsArray);\n }\n\n const triggeringField = deletableChainsAsKeys[chainAsString];\n const triggeringChain = fieldToChain(triggeringField, record);\n\n // If the inferior (deletable) chain is 1XX-based, convert the triggering better chain from 7XX to 1XX:\n if (chainContains1XX(chain)) {\n triggeringChain.forEach(f => sevenToOne(f, triggeringChain));\n }\n //nvdebug(`iRIS6C: ${chainAsString}`);\n const deletedString = fieldsToString(chain);\n const message = `DEL: '${deletedString}' REASON: '${fieldsToString(triggeringChain)}'`;\n if (fix) {\n //nvdebug(`INFERIOR $6 CHAIN REMOVAL: ${message}}`, debug);\n chain.forEach(field => record.removeField(field));\n }\n return innerRemoveInferiorChains(remainingFields, [...deletedStringsArray, message]);\n }\n\n function chainContains1XX(chain) {\n return chain.some(f => f.tag.substring(0, 1) === '1');\n }\n\n function sevenToOne(field, chain) { // Change 7XX field to 1XX field. Also handle the corresponding 880$6 7XX-NN subfields\n // NB! This function should be called only if the original 1XX gets deleted!\n if (!['700', '710', '711', '730'].includes(field.tag)) {\n return;\n }\n // Retag field 7XX as 1XX and fix corresponding occurrence numbers as well:\n const pairs = fieldGetOccurrenceNumberPairs(field, chain);\n field.tag = `1${field.tag.substring(1)}`;\n // There should always be one pair, but I'm not sanity-checking this\n pairs.forEach(pairedField => fieldSevenToOneOccurrenceNumber(pairedField));\n }\n\n}\n\n\nfunction getIdentifierlessAndKeeplessSubsets(fieldAsString) {\n // The rules below are not perfect (in complex cases they don't catch all permutations), but good enough:\n // Remove identifier(s) (MELKEHITYS-2383-ish):\n\n const identifierlessString = fieldAsString.replace(/ \u2021[01] [^\u2021]+($| \u2021)/u, '$1');\n const keeplessString = fieldAsString.replace(/ \u20219 [A-Z]+<KEEP>/u, '');\n\n return [identifierlessString, keeplessString].filter(val => val !== fieldAsString);\n}\n\nfunction deriveIndividualDeletables490(todoList, deletables = []) {\n const [fieldAsString, ...stillToDo] = todoList;\n if (fieldAsString === undefined) {\n return deletables;\n }\n //nvdebug(`PROCESS ${fieldAsString}`);\n if (!fieldAsString.match(/^490/u)) {\n return deriveIndividualDeletables490(stillToDo, deletables);\n }\n\n // $6-less version (keep this first)\n const sixless = fieldAsString.replace(/ \u20216 [^\u2021]+ \u2021/u, ' \u2021');\n\n // Without final $v or $x:\n const withoutFinalVOrX = fieldAsString.replace(/ *[;,] \u2021[vx] [^\u2021]+$/u, '');\n // Add intermediate $x-less version\n const xless = fieldAsString.replace(/, \u2021x [^\u2021]+(, \u2021x| ; \u2021v)/u, '$1');\n\n // Add $xv-less version (handled by recursion?)\n const xvless = fieldAsString.replace(/, \u2021x [^\u2021]+ \u2021v [^\u2021]+$/u, '');\n\n // MRA-433-ish (non-chain): 490 ind1=1 vs ind1=0: remove latter\n const modifiedInd2 = fieldAsString.match(/^490 1/u) ? `490 0${fieldAsString.substring(5)}` : fieldAsString;\n\n const arr = [sixless, withoutFinalVOrX, xless, xvless, modifiedInd2].filter(val => val !== fieldAsString);\n\n /*\n if (arr.length) {\n nvdebug(`${arr.length} derivation(s) for ${fieldAsString}`);\n nvdebug(arr.join('\\n'));\n }\n */\n return arr;\n}\n\nfunction deriveIndividualDeletables(record) {\n const todoList = record.fields.map(f => fieldToString(f));\n //const finishedRecord = encodingLevelIsBetterThanPrepublication(getEncodingLevel(record));\n\n const deletableStringsArray = processTodoList(todoList);\n\n const inferiorTerms = getInferiorTerms(record);\n\n return uniqArray([...deletableStringsArray, ...inferiorTerms]);\n\n function getInferiorTerms(record) {\n const inputFields = record.fields.filter(f => ['648', '650', '651'].includes(f.tag) && f.subfields);\n const result = inputFields.flatMap(f => fieldToInferiorFields(f));\n\n // console.log(result.join('\\n')); // eslint-disable-line no-console\n return result;\n }\n\n function fieldToInferiorFields(field) {\n const aArray = field.subfields.filter(sf => sf.code === 'a');\n if (field.tag === '650') {\n return aArray.flatMap(sf => [`653 ## \u2021a ${sf.value}`, `653 #0 \u2021a ${sf.value}`]);\n }\n return aArray.map(sf => `653 ## \u2021a ${sf.value}`);\n }\n\n function processTodoList(thingsToDo, deletables = []) {\n const [currString, ...stillToDo] = thingsToDo;\n\n if (currString === undefined) {\n return deletables;\n }\n\n const accentless = getAccentlessVersion(currString);\n const d490 = deriveIndividualDeletables490([currString]);\n const subsets = getIdentifierlessAndKeeplessSubsets(currString);\n const moreToDo = [...accentless, ...d490, ...subsets];\n\n\n if (currString.match(/^[1678]00/u)) {\n // Proof-of-concept rule. Should be improved eventually...\n if (currString.match(/, \u2021e [^\u2021]+\\.$/u)) {\n const tmp = currString.replace(/, \u2021e [^\u2021]+\\.$/u, '.');\n return processTodoList([tmp, ...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n }\n\n if (currString.match(/^500 ## \u2021a Lis\u00E4painokset: Lis\u00E4painos /u)) { // MET-569\n const tmp1 = currString.replace(' Lis\u00E4painos ', ' [Lis\u00E4painos] ');\n const tmp2 = currString.replace(' Lis\u00E4painos ', ' ');\n if (tmp1 !== currString && tmp2 !== currString) {\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp1, tmp2]);\n }\n }\n\n if (currString.match(/^500 ## \u2021a Lis\u00E4painokset: \\[Lis\u00E4painos\\] /u)) { // MET-569\n const tmp = currString.replace(' [Lis\u00E4painos] ', ' ');\n if (tmp !== currString) {\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n }\n\n if (currString.match(/^500 ## \u2021a Ei vastaanotettu\\.$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '500 ## \u2021a EI VASTAANOTETTU.']);\n }\n if (currString.match(/^500 ## \u2021a Ei ilmesty\\.$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '500 ## \u2021a EI ILMESTY.']);\n }\n\n if (currString.match(/^505 .0.*-- \u2021t/u)) { // MRA-413-ish\n const tmp = currString.replace(/ -- \u2021t /gu, ' -- '). // remove non-initial $t subfields\n replace(/ \u2021[rg] /gu, ' '). // remove $r and $g subfields\n replace(/ \u2021t /u, ' \u2021a '). // change first $t to $a\n // ind2: '1' => '#':\n replace(/^505 (.)0/u, '505 $1#');\n if (tmp !== currString) {\n return processTodoList([tmp, ...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n //nvdebug(`505 ORIGINAL: '${fieldAsString}'`)\n //nvdebug(`505 DERIVATE: '${tmp}'`)\n }\n\n if (currString.match(/^594 ## \u2021a Ei vastaanotettu \u20215 FENNI$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '594 ## \u2021a EI VASTAANOTETTU \u20215 FENNI']);\n }\n if (currString.match(/^594 ## \u2021a Ei ilmesty \u20215 FENNI$/u)) { // MELKEHITYS-3147\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, '594 ## \u2021a EI ILMESTY \u20215 FENNI']);\n }\n\n // MET-381: remove occurence number TAG-00, if TAG-NN existists\n if (currString.match(/^880.* \u20216 [0-9][0-9][0-9]-(?:[1-9][0-9]|0[1-9])/u)) {\n const tmp = currString.replace(/( \u20216 [0-9][0-9][0-9])-[0-9]+/u, '$1-00');\n //nvdebug(`MET-381: ADD TO DELETABLES: '${tmp}'`);\n //deletableStringsArray.push(tmp);\n if (tmp.match(/ \u20216 [0-9][0-9][0-9]-00\\/[^ ]+ /u)) {\n const tmp2 = tmp.replace(/( \u20216 [0-9][0-9][0-9]-00)[^ ]+/u, '$1');\n //nvdebug(`MET-381: ADD TO DELETABLES: '${tmp2}'`);\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp, tmp2]);\n }\n return processTodoList([...stillToDo, ...moreToDo], [...deletables, tmp]);\n }\n\n // MET-575 (merge: applies in postprocessing)\n const inferiorTerms = getPrepublicationTerms(currString);\n\n // MELKEHITYS-3277-ish: non-AI is better than AI (a rare case where longer version is inferior):\n const aiBased = `${currString} \u20217 (dpenmw)AI`;\n\n const newDeletables = [...deletables, ...subsets, ...accentless, ...d490, ...inferiorTerms, aiBased];\n\n if (subsets.length) {\n return processTodoList([...stillToDo, ...moreToDo], newDeletables);\n }\n\n return processTodoList([...stillToDo, ...moreToDo], newDeletables);\n }\n\n function getAccentlessVersion(string) { // MET-527\n //nvdebug(`START: '${string}`);\n // This is a sanity check: if precomposition does something, there's something wrong, and we don't want to proceed..\n if (string !== precomposeFinnishLetters(string)) {\n return [];\n }\n const accentless = String(fixComposition(string)).replace(/\\p{Diacritic}/gu, '');\n //nvdebug(`FROM '${string}'\\n TO '${accentless}'`);\n if (accentless === string) { // Don't self-destruct\n return [];\n }\n return [accentless];\n }\n\n function getPrepublicationTerms(fieldAsString) {\n const subfield7Prepub = `${fieldAsString} \u20217 Ennakkotieto`\n if (fieldAsString.match(/^653./u)) {\n // MET-528 (extented by MET-575)\n return [subfield7Prepub, `${fieldAsString} \u2021g ENNAKKOTIETO`, `${fieldAsString} \u2021g Ennakkotieto`, `${fieldAsString} \u2021g ennakkotieto`, `${fieldAsString} \u2021g ENNAKKOTIETO.`, `${fieldAsString} \u2021g Ennakkotieto.`, `${fieldAsString} \u2021g ennakkotieto.`];\n }\n\n return [subfield7Prepub];\n }\n\n}\n\nfunction fieldToNormalizedString(field) {\n const normalizedField = cloneAndNormalizeFieldForComparison(field);\n return fieldToString(normalizedField);\n}\n\nfunction deriveIndividualNormalizedDeletables(record) { // MET-461:\n const encodingLevel = getEncodingLevel(record);\n const recordIsFinished = encodingLevelIsBetterThanPrepublication(encodingLevel);\n const met495 = encodingLevel === '2' && record.fields.some(f => f.tag === '500' && fieldRefersToKoneellisestiTuotettuTietue(f));\n if (!recordIsFinished || met495) {\n return [];\n }\n const relevantFields = record.fields.filter(f => ['245', '246'].includes(f.tag) && fieldHasSubfield(f, 'a'));\n\n return deriveDeletable946s(relevantFields);\n\n function deriveDeletable946s(fields, results = []) {\n const [currField, ...remainingFields] = fields;\n if (currField === undefined) {\n return results;\n }\n\n const fieldAsNormalizedString = fieldToNormalizedString(currField);\n const tmp = fieldAsNormalizedString.replace(/^(?:...) ../u, '946 ##'). // <= Change tag to 946 and indicators to '##'\n replace(' \u2021a ', ' \u2021i nimeke onixissa \u2021a '). // Add $i before $a. NB! This is added in the normalized lower-cased form!\n replace(/(?: \\/)? \u2021c[^\u2021]+$/u, ''); // Remove $c. (Can $c be non-last?)\n const candArray = [tmp, `${tmp} \u20215 MELINDA`].filter(val => val !== fieldAsNormalizedString);\n if (candArray.length) {\n return deriveDeletable946s(remainingFields, [...results, ...candArray]);\n }\n return deriveDeletable946s(remainingFields, results);\n }\n}\n\nexport function removeIndividualInferiorDatafields(record, fix = true) { // No $6 nor $8 in field\n const deletableFieldsAsStrings = deriveIndividualDeletables(record);\n const deletableFieldsAsNormalizedStrings = deriveIndividualNormalizedDeletables(record);\n\n // nvdebug(`Deletables:\\n ${deletableFieldsAsStrings.join('\\n ')}`);\n // nvdebug(`Normalized deletables:\\n ${deletableFieldsAsNormalizedStrings.join('\\n ')}`);\n\n const hits = record.fields.filter(field => isDeletableField(field));\n\n const deletedFieldsAsStrings = hits.map(f => fieldToString(f));\n\n if (fix) {\n hits.forEach(field => {\n //nvdebug(`Remove inferior field: ${fieldToString(field)}`, debug);\n record.removeField(field);\n });\n }\n\n return deletedFieldsAsStrings;\n\n function isDeletableField(field) {\n const fieldAsString = fieldToString(field);\n if (deletableFieldsAsStrings.includes(fieldAsString)) {\n return true;\n }\n const fieldAsNormalizedString = fieldToNormalizedString(field);\n if (deletableFieldsAsNormalizedStrings.includes(fieldAsNormalizedString)) {\n return true;\n }\n\n return false;\n }\n}\n\n\nexport function removeInferiorDatafields(record, fix = true) {\n const removables = removeIndividualInferiorDatafields(record, fix); // Lone fields\n //const removables8 = removeDuplicateSubfield8Chains(record, fix); // Lone subfield $8 chains\n const removables6 = removeInferiorChains(record, fix); // Lone subfield $6 chains\n // HOW TO HANDLE $6+$8 combos? Skipping is relatively OK.\n\n //nvdebug(`REMOVABLES:\\n ${removables.join('\\n ')}`, debug);\n //nvdebug(`REMOVABLES 6:\\n ${removables6.join('\\n ')}`, debug);\n\n const removablesAll = removables.concat(removables6); //.concat(removables8);\n\n return removablesAll;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["fields", "record", "inferiorTerms"]
|
|
7
7
|
}
|
package/dist/sortSubfields.js
CHANGED
|
@@ -3,8 +3,8 @@ import createDebugLogger from "debug";
|
|
|
3
3
|
import { fieldToString, nvdebug } from "./utils.js";
|
|
4
4
|
const debug = createDebugLogger("@natlibfi/marc-record-validators-melinda:sortSubfields");
|
|
5
5
|
const debugDev = debug.extend("dev");
|
|
6
|
-
const defaultSortOrderStringFinns = "
|
|
7
|
-
const defaultSortOrderStringOthers = "
|
|
6
|
+
const defaultSortOrderStringFinns = "863abcdefghijklmnopqrstuvwxyz4201759";
|
|
7
|
+
const defaultSortOrderStringOthers = "863abcdefghijklmnopqrstuvwxyz4021759";
|
|
8
8
|
const defaultSortOrderFinns = defaultSortOrderStringFinns.split("");
|
|
9
9
|
const defaultSortOrderOthers = defaultSortOrderStringOthers.split("");
|
|
10
10
|
export default function(defaultTagPattern) {
|
|
@@ -48,7 +48,7 @@ export default function(defaultTagPattern) {
|
|
|
48
48
|
const sortOrderForX00 = ["i", "a", "b", "q", "c", "d", "e", "t", "u", "l", "f", "x", "y", "z", "0", "1", "5", "9"];
|
|
49
49
|
const sortOrderForX10 = ["i", "a", "b", "t", "n", "c", "e", "v", "w", "x", "y", "z", "0", "1", "5", "9"];
|
|
50
50
|
const sortOrderForX11 = ["a", "n", "d", "c", "e", "g", "j", "0", "1", "5", "9"];
|
|
51
|
-
const
|
|
51
|
+
const sortOrderFor7XXLinkingEntries = ["8", "7", "i", "a", "s", "t", "b", "c", "d", "m", "h", "k", "o", "x", "z", "g", "q", "w", "0", "1", "l", "9", "5"];
|
|
52
52
|
const sortOrderFor246 = ["i", "a", "b", "n", "p", "f", "5", "9"];
|
|
53
53
|
const subfieldSortOrder = [
|
|
54
54
|
{ "tag": "017", "sortOrder": ["i", "a", "b", "d"] },
|
|
@@ -85,22 +85,22 @@ const subfieldSortOrder = [
|
|
|
85
85
|
{ "tag": "700", "sortOrder": sortOrderForX00 },
|
|
86
86
|
{ "tag": "710", "sortOrder": sortOrderForX10 },
|
|
87
87
|
{ "tag": "711", "sortOrder": sortOrderForX11 },
|
|
88
|
-
{ "tag": "760", "sortOrder":
|
|
89
|
-
{ "tag": "762", "sortOrder":
|
|
90
|
-
{ "tag": "765", "sortOrder":
|
|
91
|
-
{ "tag": "767", "sortOrder":
|
|
92
|
-
{ "tag": "770", "sortOrder":
|
|
93
|
-
{ "tag": "772", "sortOrder":
|
|
94
|
-
{ "tag": "773", "sortOrder":
|
|
95
|
-
{ "tag": "774", "sortOrder":
|
|
96
|
-
{ "tag": "775", "sortOrder":
|
|
97
|
-
{ "tag": "776", "sortOrder":
|
|
98
|
-
{ "tag": "777", "sortOrder":
|
|
99
|
-
{ "tag": "780", "sortOrder":
|
|
100
|
-
{ "tag": "785", "sortOrder":
|
|
101
|
-
{ "tag": "786", "sortOrder":
|
|
102
|
-
{ "tag": "787", "sortOrder":
|
|
103
|
-
{ "tag": "788", "sortOrder":
|
|
88
|
+
{ "tag": "760", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
89
|
+
{ "tag": "762", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
90
|
+
{ "tag": "765", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
91
|
+
{ "tag": "767", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
92
|
+
{ "tag": "770", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
93
|
+
{ "tag": "772", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
94
|
+
{ "tag": "773", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
95
|
+
{ "tag": "774", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
96
|
+
{ "tag": "775", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
97
|
+
{ "tag": "776", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
98
|
+
{ "tag": "777", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
99
|
+
{ "tag": "780", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
100
|
+
{ "tag": "785", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
101
|
+
{ "tag": "786", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
102
|
+
{ "tag": "787", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
103
|
+
{ "tag": "788", "sortOrder": sortOrderFor7XXLinkingEntries },
|
|
104
104
|
{ "tag": "800", "sortOrder": sortOrderForX00 },
|
|
105
105
|
{ "tag": "810", "sortOrder": sortOrderForX10 },
|
|
106
106
|
{ "tag": "811", "sortOrder": sortOrderForX11 },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/sortSubfields.js"],
|
|
4
|
-
"sourcesContent": ["// Author(s): Nicholas Volk\n\nimport clone from 'clone';\nimport createDebugLogger from 'debug';\nimport {fieldToString, nvdebug} from './utils.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortSubfields');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst defaultSortOrderStringFinns = '8673abcdefghijklmnopqrstuvwxyz420159'; // NB! We Finns like $2 before $0 in 6XX...\nconst defaultSortOrderStringOthers = '8673abcdefghijklmnopqrstuvwxyz402159';\n\nconst defaultSortOrderFinns = defaultSortOrderStringFinns.split('');\nconst defaultSortOrderOthers = defaultSortOrderStringOthers.split('');\n\n\nexport default function (defaultTagPattern) {\n\n return {\n description: 'Swap adjacent subfields',\n validate, fix\n };\n\n function getRelevantFields(record, tagPattern) {\n const datafields = record.fields.filter(f => f.subfields);\n if (!tagPattern) {\n return datafields;\n }\n\n const regexp = new RegExp(tagPattern, 'u');\n return datafields.filter(f => regexp.test(f.tag));\n }\n\n function fix(record, tagPattern = defaultTagPattern) {\n const res = {message: [], fix: [], valid: true};\n\n const relevantFields = getRelevantFields(record, tagPattern);\n\n relevantFields.forEach(field => {\n sortAdjacentSubfields(field);\n });\n\n return res;\n }\n\n function validate(record, tagPattern = defaultTagPattern) {\n const res = {message: []};\n\n const relevantFields = getRelevantFields(record, tagPattern);\n\n relevantFields.forEach(field => {\n const clonedField = clone(field);\n sortAdjacentSubfields(clonedField);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) {\n res.message.push(clonedFieldAsString);\n }\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n}\n\n\n// X00, X10, X11 and X130 could also for their own sets...\n// (ouch! sometimes $c comes after $d...): LoC: 100 0# \u2021a Black Foot, \u2021c Chief, \u2021d d. 1877 \u2021c (Spirit)\nconst sortOrderForX00 = ['i', 'a', 'b', 'q', 'c', 'd', 'e', 't', 'u', 'l', 'f', 'x', 'y', 'z', '0', '1', '5', '9']; // skip $g. Can't remember why, though...\nconst sortOrderForX10 = ['i', 'a', 'b', 't', 'n', 'c', 'e', 'v', 'w', 'x', 'y', 'z', '0', '1', '5', '9']; // somewhat iffy\nconst sortOrderForX11 = ['a', 'n', 'd', 'c', 'e', 'g', 'j', '0', '1', '5', '9'];\nconst sortOrderFor7XX = ['8', '7', 'i', 'a', 's', 't', 'b', 'c', 'd', 'm', 'h', 'k', 'o', 'x', 'z', 'g', 'q', 'w'];\nconst sortOrderFor246 = ['i', 'a', 'b', 'n', 'p', 'f', '5', '9']; // Used by field 946 as well\n\n// List *only* exceptional order here. Otherwise default order is used.\nconst subfieldSortOrder = [\n {'tag': '017', 'sortOrder': ['i', 'a', 'b', 'd']},\n {'tag': '028', 'sortOrder': ['b', 'a', 'q']}, // National convention\n //{'tag': '031', 'sortOrder': ['a', 'b', 'c', 'm', 'e', 'd']}, // utter guesswork\n {'tag': '040', 'sortOrder': ['8', 'a', 'b', 'e', 'c', 'd', 'x']},\n // rda mus: 041: k < h < e < n < g < m < j (I think h<e is bad)\n // rda: g < h, j < p < h, i < j, k < h\n // loc: b < j, $m follows $b or $g\n // NV: $a \n {'tag': '041', 'sortOrder': ['8', 'a', 'd', 'e', 'b', 'f', 'i', 'j', 'p', 'k', 'h', 'n', 'g', 'm']}, // guesswork\n {'tag': '048', 'sortOrder': ['8', 'b', 'a']},\n {'tag': '100', 'sortOrder': sortOrderForX00},\n {'tag': '110', 'sortOrder': sortOrderForX10},\n {'tag': '111', 'sortOrder': sortOrderForX11},\n {'tag': '130', 'sortOrder': ['a', 'n', 'p', 'k', 'l']},\n {'tag': '240', 'sortOrder': ['a', 'm', 'n', 'p', 's', 'l', '2', '0', '1', '5', '9']},\n {'tag': '245', 'sortOrder': ['a', 'b', 'n', 'p', 'k', 'f', 'c']},\n {'tag': '246', 'sortOrder': sortOrderFor246},\n {'tag': '382', 'sortOrder': ['a']},\n {'tag': '385', 'sortOrder': ['8', 'm', 'n', 'a', '2', '0', '1']},\n {'tag': '386', 'sortOrder': ['8', 'm', 'n', 'a']},\n {'tag': '490', 'sortOrder': ['a', 'x', 'y', 'v', 'l']},\n {'tag': '505', 'sortOrder': ['a']},\n {'tag': '526', 'sortOrder': ['i', 'a', 'b', 'x', 'z']},\n {'tag': '534', 'sortOrder': ['3', 'p', 'a', 't', 'l', 'c', 'f', 'b', 'e', 'o', 'x', 'z']},\n {'tag': '540', 'sortOrder': ['a', 'b', 'c', 'd', 'f', '2', 'u']},\n {'tag': '600', 'sortOrder': sortOrderForX00},\n {'tag': '610', 'sortOrder': sortOrderForX10},\n {'tag': '611', 'sortOrder': sortOrderForX11},\n {'tag': '650', 'sortOrder': ['a', 'x', 'y', 'z']},\n {'tag': '700', 'sortOrder': sortOrderForX00},\n {'tag': '710', 'sortOrder': sortOrderForX10},\n {'tag': '711', 'sortOrder': sortOrderForX11},\n {'tag': '760', 'sortOrder': sortOrderFor7XX},\n {'tag': '762', 'sortOrder': sortOrderFor7XX},\n {'tag': '765', 'sortOrder': sortOrderFor7XX},\n {'tag': '767', 'sortOrder': sortOrderFor7XX},\n {'tag': '770', 'sortOrder': sortOrderFor7XX},\n {'tag': '772', 'sortOrder': sortOrderFor7XX},\n {'tag': '773', 'sortOrder': sortOrderFor7XX},\n {'tag': '774', 'sortOrder': sortOrderFor7XX},\n {'tag': '775', 'sortOrder': sortOrderFor7XX},\n {'tag': '776', 'sortOrder': sortOrderFor7XX},\n {'tag': '777', 'sortOrder': sortOrderFor7XX},\n {'tag': '780', 'sortOrder': sortOrderFor7XX},\n {'tag': '785', 'sortOrder': sortOrderFor7XX},\n {'tag': '786', 'sortOrder': sortOrderFor7XX},\n {'tag': '787', 'sortOrder': sortOrderFor7XX},\n {'tag': '788', 'sortOrder': sortOrderFor7XX},\n {'tag': '800', 'sortOrder': sortOrderForX00},\n {'tag': '810', 'sortOrder': sortOrderForX10},\n {'tag': '811', 'sortOrder': sortOrderForX11},\n {'tag': '830', 'sortOrder': ['a', 'n', 'x', 'v']}, // INCOMPLETE, SAME AS 490? APPARENTLY NOT...\n {'tag': '856', 'sortOrder': ['3', 'u', 'q', 'x', 'y', 'z', '5']}, // incomplete, LoC examples are inconclusive\n {'tag': '880', 'sortOrder': ['a']},\n {'tag': '946', 'sortOrder': sortOrderFor246},\n {'tag': 'LOW', 'sortOrder': ['a', 'b', 'c', 'l', 'h']},\n {'tag': 'SID', 'sortOrder': ['c', 'b']} // Hack, so that default order is not used\n];\n\nfunction getSubfieldSortOrder(field) {\n const entry = subfieldSortOrder.filter(currEntry => field.tag === currEntry.tag);\n if (entry.length > 0 && 'sortOrder' in entry[0]) {\n debugDev(`sort order for ${field.tag}: ${entry[0].sortOrder}`);\n return entry[0].sortOrder;\n }\n if (!['300'].includes(field.tag)) { // Lis tags which use normal $a...$z order here!\n nvdebug(`WARNING!\\tNo subfield order found for ${field.tag}.`);\n }\n return [];\n}\n\n\nfunction swapSubfields(field, sortOrder) {\n if (!field.subfields) {\n return;\n }\n\n const loopAgain = field.subfields.some((sf, index) => {\n if (index === 0) {\n return false;\n }\n const currPos = getPosition(sf, sortOrder);\n const prevPos = getPosition(field.subfields[index - 1], sortOrder);\n if (currPos === -1 || prevPos === -1 || currPos >= prevPos) {\n return false;\n }\n // Swap:\n const tmp = field.subfields[index - 1];\n field.subfields[index - 1] = sf;\n field.subfields[index] = tmp;\n return true;\n });\n\n if (loopAgain) {\n return swapSubfields(field, sortOrder);\n }\n\n return;\n\n function getPosition(subfield, sortOrder) {\n // Magic exception that *always* comes first, used by Aleph in linking overlong fields\n if (sortOrder.indexOf('9') > -1 && subfield.code === '9' && ['^', '^^'].includes(subfield.value)) {\n return -0.5; // normal \"best value\" is 0, and \"worst value\" is N\n }\n return sortOrder.indexOf(subfield.code);\n }\n}\n\n\nfunction twoBeforeZero(field) {\n const sf2 = field.subfields.filter(sf => sf.code === '2');\n if (sf2.length !== 1) {\n return true; // both true and false are ok here\n }\n // MRA-465: gcipplatform (field 753)\n // rdasco (344), creatorbio (353), gbd (668), lsch (eg. 385)\n if (['creatorbio', 'gbd', 'gcipplatform', 'lscsh', 'rdasco'].includes(sf2[0].value)) {\n return false;\n }\n return true;\n}\n\nfunction moveSubfield6ToTheFront(field) {\n // https://www.loc.gov/marc/bibliographic/ecbdcntf.html says \"Subfield $6 is always the first subfield in the field.\"\n const sf6s = field.subfields.filter(sf => sf.code === '6');\n const others = field.subfields.filter(sf => sf.code !== '6');\n field.subfields = [...sf6s, ...others];\n}\n\nexport function sortAdjacentSubfields(field, externalSortOrder = []) {\n if (!field.subfields) {\n return field;\n }\n\n moveSubfield6ToTheFront(field); // specs: \"Subfield $6 is always the first subfield in the field.\"\n\n // Features:\n // - Swap only sort adjacent pairs.\n // - No sorting over unlisted subfield codes. Thus a given subfield can not shift to wrong side of 700$t...\n\n // Implement: 880 field should use values from $6...\n\n // Should we support multiple sort orders per field?\n\n // Try to handle control subfield order. This is not 100% fool proof. Control subfields are pretty stable, though.\n // However, there are exceptions (eg. $9 ^^ comes first and $2 $0 is a Finnish convention...)\n\n\n const finnishWay = twoBeforeZero(field);\n\n // Note: 760-789: '7' comes way earlier (after '6' and '8')\n const controlSubfieldOrder = finnishWay ? ['8', '3', 'a', '4', '2', '0', '1', '7', '5', '9'] : ['8', '7', '3', 'a', '4', '0', '1', '2', '7', '5', '9'];\n swapSubfields(field, controlSubfieldOrder);\n\n const sortOrderForField = externalSortOrder.length > 0 ? externalSortOrder : getSubfieldSortOrder(field);\n //nvdebug(`INTERMEDIATE SUBFIELD ORDER FOR ${field.tag}: ${sortOrderForField.join(', ')}`);\n\n const defaultSortOrder = finnishWay ? defaultSortOrderFinns : defaultSortOrderOthers; // $2 vs $0\n const subfieldOrder = sortOrderForField.length > 0 ? sortOrderForField : defaultSortOrder;\n //nvdebug(`FINAL SUBFIELD ORDER (FINNISH=${finnishWay}) FOR ${field.tag}: ${subfieldOrder.join(', ')}`);\n //if (sortOrder === null) { return field; } //// Currently always sort..\n //nvdebug(`IN: ${fieldToString(field)}`);\n swapSubfields(field, subfieldOrder);\n //nvdebug(`OUT: ${fieldToString(field)}`);\n\n return field;\n}\n\n"],
|
|
5
|
-
"mappings": "AAEA,OAAO,WAAW;AAClB,OAAO,uBAAuB;AAC9B,SAAQ,eAAe,eAAc;AAErC,MAAM,QAAQ,kBAAkB,wDAAwD;AAExF,MAAM,WAAW,MAAM,OAAO,KAAK;AAEnC,MAAM,8BAA8B;AACpC,MAAM,+BAA+B;AAErC,MAAM,wBAAwB,4BAA4B,MAAM,EAAE;AAClE,MAAM,yBAAyB,6BAA6B,MAAM,EAAE;AAGpE,wBAAyB,mBAAmB;AAE1C,SAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IAAU;AAAA,EACZ;AAEA,WAAS,kBAAkB,QAAQ,YAAY;AAC7C,UAAM,aAAa,OAAO,OAAO,OAAO,OAAK,EAAE,SAAS;AACxD,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,IAAI,OAAO,YAAY,GAAG;AACzC,WAAO,WAAW,OAAO,OAAK,OAAO,KAAK,EAAE,GAAG,CAAC;AAAA,EAClD;AAEA,WAAS,IAAI,QAAQ,aAAa,mBAAmB;AACnD,UAAM,MAAM,EAAC,SAAS,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,KAAI;AAE9C,UAAM,iBAAiB,kBAAkB,QAAQ,UAAU;AAE3D,mBAAe,QAAQ,WAAS;AAC9B,4BAAsB,KAAK;AAAA,IAC7B,CAAC;AAED,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,QAAQ,aAAa,mBAAmB;AACxD,UAAM,MAAM,EAAC,SAAS,CAAC,EAAC;AAExB,UAAM,iBAAiB,kBAAkB,QAAQ,UAAU;AAE3D,mBAAe,QAAQ,WAAS;AAC9B,YAAM,cAAc,MAAM,KAAK;AAC/B,4BAAsB,WAAW;AACjC,YAAM,sBAAsB,cAAc,WAAW;AACrD,YAAM,gBAAgB,cAAc,KAAK;AACzC,UAAI,kBAAkB,qBAAqB;AACzC,YAAI,QAAQ,KAAK,mBAAmB;AAAA,MACtC;AAAA,IACF,CAAC;AAED,QAAI,QAAQ,EAAE,IAAI,QAAQ,UAAU;AACpC,WAAO;AAAA,EACT;AACF;AAKA,MAAM,kBAAkB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACjH,MAAM,kBAAkB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACvG,MAAM,kBAAkB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAC9E,MAAM,
|
|
4
|
+
"sourcesContent": ["// Author(s): Nicholas Volk\n\nimport clone from 'clone';\nimport createDebugLogger from 'debug';\nimport {fieldToString, nvdebug} from './utils.js';\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortSubfields');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nconst defaultSortOrderStringFinns = '863abcdefghijklmnopqrstuvwxyz4201759'; // NB! We Finns like $2 before $0 in 6XX...\nconst defaultSortOrderStringOthers = '863abcdefghijklmnopqrstuvwxyz4021759'; // NB 760-788 have '7' in different position...\n\nconst defaultSortOrderFinns = defaultSortOrderStringFinns.split('');\nconst defaultSortOrderOthers = defaultSortOrderStringOthers.split('');\n\n\nexport default function (defaultTagPattern) {\n\n return {\n description: 'Swap adjacent subfields',\n validate, fix\n };\n\n function getRelevantFields(record, tagPattern) {\n const datafields = record.fields.filter(f => f.subfields);\n if (!tagPattern) {\n return datafields;\n }\n\n const regexp = new RegExp(tagPattern, 'u');\n return datafields.filter(f => regexp.test(f.tag));\n }\n\n function fix(record, tagPattern = defaultTagPattern) {\n const res = {message: [], fix: [], valid: true};\n\n const relevantFields = getRelevantFields(record, tagPattern);\n\n relevantFields.forEach(field => {\n sortAdjacentSubfields(field);\n });\n\n return res;\n }\n\n function validate(record, tagPattern = defaultTagPattern) {\n const res = {message: []};\n\n const relevantFields = getRelevantFields(record, tagPattern);\n\n relevantFields.forEach(field => {\n const clonedField = clone(field);\n sortAdjacentSubfields(clonedField);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) {\n res.message.push(clonedFieldAsString);\n }\n });\n\n res.valid = !(res.message.length >= 1);\n return res;\n }\n}\n\n\n// X00, X10, X11 and X130 could also for their own sets...\n// (ouch! sometimes $c comes after $d...): LoC: 100 0# \u2021a Black Foot, \u2021c Chief, \u2021d d. 1877 \u2021c (Spirit)\nconst sortOrderForX00 = ['i', 'a', 'b', 'q', 'c', 'd', 'e', 't', 'u', 'l', 'f', 'x', 'y', 'z', '0', '1', '5', '9']; // skip $g. Can't remember why, though...\nconst sortOrderForX10 = ['i', 'a', 'b', 't', 'n', 'c', 'e', 'v', 'w', 'x', 'y', 'z', '0', '1', '5', '9']; // somewhat iffy\nconst sortOrderForX11 = ['a', 'n', 'd', 'c', 'e', 'g', 'j', '0', '1', '5', '9'];\nconst sortOrderFor7XXLinkingEntries = ['8', '7', 'i', 'a', 's', 't', 'b', 'c', 'd', 'm', 'h', 'k', 'o', 'x', 'z', 'g', 'q', 'w', '0', '1', 'l', '9', '5'];\nconst sortOrderFor246 = ['i', 'a', 'b', 'n', 'p', 'f', '5', '9']; // Used by field 946 as well\n\n// List *only* exceptional order here. Otherwise default order is used.\nconst subfieldSortOrder = [\n {'tag': '017', 'sortOrder': ['i', 'a', 'b', 'd']},\n {'tag': '028', 'sortOrder': ['b', 'a', 'q']}, // National convention\n //{'tag': '031', 'sortOrder': ['a', 'b', 'c', 'm', 'e', 'd']}, // utter guesswork\n {'tag': '040', 'sortOrder': ['8', 'a', 'b', 'e', 'c', 'd', 'x']},\n // rda mus: 041: k < h < e < n < g < m < j (I think h<e is bad)\n // rda: g < h, j < p < h, i < j, k < h\n // loc: b < j, $m follows $b or $g\n // NV: $a \n {'tag': '041', 'sortOrder': ['8', 'a', 'd', 'e', 'b', 'f', 'i', 'j', 'p', 'k', 'h', 'n', 'g', 'm']}, // guesswork\n {'tag': '048', 'sortOrder': ['8', 'b', 'a']},\n {'tag': '100', 'sortOrder': sortOrderForX00},\n {'tag': '110', 'sortOrder': sortOrderForX10},\n {'tag': '111', 'sortOrder': sortOrderForX11},\n {'tag': '130', 'sortOrder': ['a', 'n', 'p', 'k', 'l']},\n {'tag': '240', 'sortOrder': ['a', 'm', 'n', 'p', 's', 'l', '2', '0', '1', '5', '9']},\n {'tag': '245', 'sortOrder': ['a', 'b', 'n', 'p', 'k', 'f', 'c']},\n {'tag': '246', 'sortOrder': sortOrderFor246},\n {'tag': '382', 'sortOrder': ['a']},\n {'tag': '385', 'sortOrder': ['8', 'm', 'n', 'a', '2', '0', '1']},\n {'tag': '386', 'sortOrder': ['8', 'm', 'n', 'a']},\n {'tag': '490', 'sortOrder': ['a', 'x', 'y', 'v', 'l']},\n {'tag': '505', 'sortOrder': ['a']},\n {'tag': '526', 'sortOrder': ['i', 'a', 'b', 'x', 'z']},\n {'tag': '534', 'sortOrder': ['3', 'p', 'a', 't', 'l', 'c', 'f', 'b', 'e', 'o', 'x', 'z']},\n {'tag': '540', 'sortOrder': ['a', 'b', 'c', 'd', 'f', '2', 'u']},\n {'tag': '600', 'sortOrder': sortOrderForX00},\n {'tag': '610', 'sortOrder': sortOrderForX10},\n {'tag': '611', 'sortOrder': sortOrderForX11},\n {'tag': '650', 'sortOrder': ['a', 'x', 'y', 'z']},\n {'tag': '700', 'sortOrder': sortOrderForX00},\n {'tag': '710', 'sortOrder': sortOrderForX10},\n {'tag': '711', 'sortOrder': sortOrderForX11},\n {'tag': '760', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '762', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '765', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '767', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '770', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '772', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '773', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '774', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '775', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '776', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '777', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '780', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '785', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '786', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '787', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '788', 'sortOrder': sortOrderFor7XXLinkingEntries},\n {'tag': '800', 'sortOrder': sortOrderForX00},\n {'tag': '810', 'sortOrder': sortOrderForX10},\n {'tag': '811', 'sortOrder': sortOrderForX11},\n {'tag': '830', 'sortOrder': ['a', 'n', 'x', 'v']}, // INCOMPLETE, SAME AS 490? APPARENTLY NOT...\n {'tag': '856', 'sortOrder': ['3', 'u', 'q', 'x', 'y', 'z', '5']}, // incomplete, LoC examples are inconclusive\n {'tag': '880', 'sortOrder': ['a']},\n {'tag': '946', 'sortOrder': sortOrderFor246},\n {'tag': 'LOW', 'sortOrder': ['a', 'b', 'c', 'l', 'h']},\n {'tag': 'SID', 'sortOrder': ['c', 'b']} // Hack, so that default order is not used\n];\n\nfunction getSubfieldSortOrder(field) {\n const entry = subfieldSortOrder.filter(currEntry => field.tag === currEntry.tag);\n if (entry.length > 0 && 'sortOrder' in entry[0]) {\n debugDev(`sort order for ${field.tag}: ${entry[0].sortOrder}`);\n return entry[0].sortOrder;\n }\n if (!['300'].includes(field.tag)) { // Lis tags which use normal $a...$z order here!\n nvdebug(`WARNING!\\tNo subfield order found for ${field.tag}.`);\n }\n return [];\n}\n\n\nfunction swapSubfields(field, sortOrder) {\n if (!field.subfields) {\n return;\n }\n\n const loopAgain = field.subfields.some((sf, index) => {\n if (index === 0) {\n return false;\n }\n const currPos = getPosition(sf, sortOrder);\n const prevPos = getPosition(field.subfields[index - 1], sortOrder);\n if (currPos === -1 || prevPos === -1 || currPos >= prevPos) {\n return false;\n }\n // Swap:\n const tmp = field.subfields[index - 1];\n field.subfields[index - 1] = sf;\n field.subfields[index] = tmp;\n return true;\n });\n\n if (loopAgain) {\n return swapSubfields(field, sortOrder);\n }\n\n return;\n\n function getPosition(subfield, sortOrder) {\n // Magic exception that *always* comes first, used by Aleph in linking overlong fields\n if (sortOrder.indexOf('9') > -1 && subfield.code === '9' && ['^', '^^'].includes(subfield.value)) {\n return -0.5; // normal \"best value\" is 0, and \"worst value\" is N\n }\n return sortOrder.indexOf(subfield.code);\n }\n}\n\n\nfunction twoBeforeZero(field) {\n const sf2 = field.subfields.filter(sf => sf.code === '2');\n if (sf2.length !== 1) {\n return true; // both true and false are ok here\n }\n // MRA-465: gcipplatform (field 753)\n // rdasco (344), creatorbio (353), gbd (668), lsch (eg. 385)\n if (['creatorbio', 'gbd', 'gcipplatform', 'lscsh', 'rdasco'].includes(sf2[0].value)) {\n return false;\n }\n return true;\n}\n\nfunction moveSubfield6ToTheFront(field) {\n // https://www.loc.gov/marc/bibliographic/ecbdcntf.html says \"Subfield $6 is always the first subfield in the field.\"\n const sf6s = field.subfields.filter(sf => sf.code === '6');\n const others = field.subfields.filter(sf => sf.code !== '6');\n field.subfields = [...sf6s, ...others];\n}\n\nexport function sortAdjacentSubfields(field, externalSortOrder = []) {\n if (!field.subfields) {\n return field;\n }\n\n moveSubfield6ToTheFront(field); // specs: \"Subfield $6 is always the first subfield in the field.\"\n\n // Features:\n // - Swap only sort adjacent pairs.\n // - No sorting over unlisted subfield codes. Thus a given subfield can not shift to wrong side of 700$t...\n\n // Implement: 880 field should use values from $6...\n\n // Should we support multiple sort orders per field?\n\n // Try to handle control subfield order. This is not 100% fool proof. Control subfields are pretty stable, though.\n // However, there are exceptions (eg. $9 ^^ comes first and $2 $0 is a Finnish convention...)\n\n\n const finnishWay = twoBeforeZero(field);\n\n // Note: 760-789: '7' comes way earlier (after '6' and '8')\n const controlSubfieldOrder = finnishWay ? ['8', '3', 'a', '4', '2', '0', '1', '7', '5', '9'] : ['8', '7', '3', 'a', '4', '0', '1', '2', '7', '5', '9'];\n swapSubfields(field, controlSubfieldOrder);\n\n const sortOrderForField = externalSortOrder.length > 0 ? externalSortOrder : getSubfieldSortOrder(field);\n //nvdebug(`INTERMEDIATE SUBFIELD ORDER FOR ${field.tag}: ${sortOrderForField.join(', ')}`);\n\n const defaultSortOrder = finnishWay ? defaultSortOrderFinns : defaultSortOrderOthers; // $2 vs $0\n const subfieldOrder = sortOrderForField.length > 0 ? sortOrderForField : defaultSortOrder;\n //nvdebug(`FINAL SUBFIELD ORDER (FINNISH=${finnishWay}) FOR ${field.tag}: ${subfieldOrder.join(', ')}`);\n //if (sortOrder === null) { return field; } //// Currently always sort..\n //nvdebug(`IN: ${fieldToString(field)}`);\n swapSubfields(field, subfieldOrder);\n //nvdebug(`OUT: ${fieldToString(field)}`);\n\n return field;\n}\n\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["sortOrder"]
|
|
7
7
|
}
|
package/dist/subfield6Utils.js
CHANGED
|
@@ -138,7 +138,6 @@ export function fieldSevenToOneOccurrenceNumber(field) {
|
|
|
138
138
|
export function fieldGetOccurrenceNumberPairs(field, candFields) {
|
|
139
139
|
const pairs = candFields.filter((otherField) => isSubfield6Pair(field, otherField));
|
|
140
140
|
if (pairs.length === 0) {
|
|
141
|
-
nvdebug(`NO PAIRS FOUND FOR '${fieldToString(field)}'`);
|
|
142
141
|
return pairs;
|
|
143
142
|
}
|
|
144
143
|
pairs.forEach((pairedField) => nvdebug(` '${fieldToString(pairedField)}'`));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/subfield6Utils.js"],
|
|
4
|
-
"sourcesContent": ["//import createDebugLogger from 'debug';\n// const debug = createDebugLogger('@natlibfi/marc-record-validator-melinda/subfield6Utils');\n\nimport {add8s, fieldsGetAllSubfield8LinkingNumbers, getSubfield8LinkingNumber, isValidSubfield8} from './subfield8Utils.js';\nimport {fieldHasSubfield, fieldToString, /* fieldsToString, */ nvdebug, subfieldToString} from './utils.js';\n\n//const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:subfield6Utils');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\n// NB! Subfield 6 is non-repeatable and it should always comes first!\n// NB! Index size should always be 2 (preceding 0 required for 01..09) However, support for 100+ was added on 2023-02-27.\n// NB! Index value '00' are left as they are (is not paired/indexed/whatever.\nconst sf6Regexp = /^[0-9][0-9][0-9]-(?:[0-9][0-9]|[1-9][0-9]+)(?:[^0-9].*)?$/u;\n\nexport function isValidSubfield6(subfield) {\n if (subfield.code !== '6') {\n return false;\n }\n return subfield.value.match(sf6Regexp);\n}\n\nexport function subfield6GetTag(subfield) {\n if (isValidSubfield6(subfield)) {\n return subfield.value.substring(0, 3);\n }\n return undefined;\n}\n\nexport function subfield6GetOccurrenceNumber(subfield) {\n if (isValidSubfield6(subfield)) {\n // Skip \"TAG-\" prefix. 2023-02-20: removed 2-digit requirement from here...\n return subfield.value.substring(4).replace(/\\D.*$/u, '');\n }\n return undefined;\n}\n\nexport function subfield6GetOccurrenceNumberAsInteger(subfield) {\n const index = subfield6GetOccurrenceNumber(subfield);\n if (index === undefined || index === '00') {\n return 0;\n }\n const result = parseInt(index, 10);\n //nvdebug(`SF6: ${subfield.value} => ${index} => ${result}`, debug);\n return result;\n}\n\nexport function subfield6ResetOccurrenceNumber(subfield, occurrenceNumber) {\n if (!isValidSubfield6(subfield)) {\n return;\n }\n const occurrenceNumberAsString = typeof occurrenceNumber === 'number' ? intToOccurrenceNumberString(occurrenceNumber) : occurrenceNumber;\n\n const newValue = subfield.value.substring(0, 4) + occurrenceNumberAsString + subfield6GetTail(subfield);\n //nvdebug(`Set subfield $6 value from ${subfieldToString(subfield)} to ${newValue}`);\n subfield.value = newValue;\n}\n\n\nfunction subfield6GetTail(subfield) {\n if (isValidSubfield6(subfield)) {\n // Skip \"TAG-\" prefix. 2023-02-20: removed 2-digit requirement from here...\n return subfield.value.replace(/^\\d+-\\d+/u, '');\n }\n return '';\n}\n\nexport function subfield6HasWantedTagAndOccurrenceNumber(subfield, tagAndOccurrenceNumber) {\n if (subfield.code !== '6') {\n return false;\n }\n // We could also use generic code and go getTag()+'-'+getIndex() instead of regexp...\n const key = subfield.value.replace(/^([0-9][0-9][0-9]-[0-9][0-9]+).*$/u, '$1');\n //nvdebug(` Compare '${key}' vs '${tagAndOccurrenceNumber}'`);\n return key === tagAndOccurrenceNumber;\n}\n\n// <= SUBFIELD, FIELD =>\n\nexport function fieldGetUnambiguousTag(field) {\n const tags = field.subfields.filter(sf => subfield6GetTag(sf));\n if (tags.length === 1) {\n return subfield6GetTag(tags[0]);\n }\n return undefined;\n}\n\nexport function fieldGetUnambiguousOccurrenceNumber(field) {\n const occurrenceNumbers = field.subfields.filter(sf => subfield6GetOccurrenceNumber(sf));\n if (occurrenceNumbers.length === 1) {\n return subfield6GetOccurrenceNumber(occurrenceNumbers[0]);\n }\n return undefined;\n}\n\nexport function fieldHasOccurrenceNumber(field, occurrenceNumber) {\n //nvdebug(`${occurrenceNumber} vs ${fieldToString(field)}`);\n return field.subfields && field.subfields.some(sf => subfield6GetOccurrenceNumber(sf) === occurrenceNumber);\n}\n\nexport function fieldResetOccurrenceNumber(field, newOccurrenceNumber, oldOccurrenceNumber = undefined) {\n field.subfields.forEach(subfield => innerReset(subfield));\n\n function innerReset(subfield) {\n // (Optional) Check that this is really the occurrence number we wan't to reseot\n if (oldOccurrenceNumber !== undefined) {\n const currOccurrenceNumber = subfield6GetOccurrenceNumber(subfield);\n if (currOccurrenceNumber !== oldOccurrenceNumber) {\n return;\n }\n }\n subfield6ResetOccurrenceNumber(subfield, newOccurrenceNumber);\n }\n}\n\nexport function intToOccurrenceNumberString(i) {\n return i < 10 ? `0${i}` : `${i}`;\n}\n\nexport function fieldGetMaxSubfield6OccurrenceNumberAsInteger(field) {\n // used by reducer!\n //nvdebug(`Checking subfields $6 from ${JSON.stringify(field)}`);\n const sf6s = field.subfields ? field.subfields.filter(subfield => isValidSubfield6(subfield)) : [];\n if (sf6s.length === 0) {\n return 0;\n }\n // There should always be one, but here we check every subfield.\n //nvdebug(`Got ${field.subfields} $6-subfield(s) from ${JSON.stringify(field)}`, debug);\n const vals = sf6s.map(sf => subfield6GetOccurrenceNumberAsInteger(sf));\n return Math.max(...vals);\n}\n\nexport function fieldHasWantedTagAndOccurrenceNumber(field, tagAndOccurrenceNumber) {\n return field.subfields && field.subfields.some(sf => subfield6HasWantedTagAndOccurrenceNumber(sf, tagAndOccurrenceNumber));\n}\n\n\n/*\nexport function getFieldsWithGivenOccurrenceNumberSubfield6(record, occurrenceNumberAsString) {\n const record.fields.filter(field => field\n\n function fieldHasIndex(field, index) {\n if (!field.subfields) {\n return false;\n }\n return field.subfields.find(sf => isValidSubfield6(sf) && subfieldGetOccurrenceNumber6(sf) === index);\n }\n}\n*/\n\n\nexport function fieldHasValidSubfield6(field) {\n return field.subfields && field.subfields.some(sf => isValidSubfield6(sf));\n}\n\nexport function isSubfield6Pair(field, otherField) {\n // No need to log this:\n //nvdebug(`LOOK for $6-pair:\\n ${fieldToString(field)}\\n ${fieldToString(otherField)}`);\n if (!fieldHasValidSubfield6(field) || !fieldHasValidSubfield6(otherField)) {\n return false;\n }\n\n if (!tagsArePairable6(field.tag, otherField.tag)) {\n //nvdebug(` FAILED. REASON: TAGS NOT PAIRABLE!`);\n return false;\n }\n\n\n const fieldIndex = fieldGetUnambiguousOccurrenceNumber(field);\n if (fieldIndex === undefined || fieldIndex === '00') {\n //nvdebug(` FAILED. REASON: NO INDEX FOUND`);\n return false;\n }\n\n const otherFieldIndex = fieldGetUnambiguousOccurrenceNumber(otherField);\n\n\n if (fieldIndex !== otherFieldIndex) {\n //nvdebug(` FAILURE: INDEXES: ${fieldIndex} vs ${otherFieldIndex}`);\n return false;\n }\n\n if (fieldGetUnambiguousTag(field) !== otherField.tag || field.tag !== fieldGetUnambiguousTag(otherField)) {\n //nvdebug(` FAILURE: TAG vs $6 TAG`);\n return false;\n }\n return true;\n\n function tagsArePairable6(tag1, tag2) {\n // How to do XOR operation in one line? Well, this is probably more readable...\n if (tag1 === '880' && tag2 === '880') {\n return false;\n }\n if (tag1 !== '880' && tag2 !== '880') {\n return false;\n }\n return true;\n }\n}\n\n\nfunction subfieldSevenToOneOccurrenceNumber(subfield) {\n if (subfield.code !== '6' || subfield.value.substring(0, 1) !== '7') {\n return;\n }\n subfield.value = `1${subfield.value.substring(1)}`;\n}\n\nexport function fieldSevenToOneOccurrenceNumber(field) {\n if (field.tag !== '880') {\n return;\n }\n field.subfields.forEach(sf => subfieldSevenToOneOccurrenceNumber(sf));\n}\n\n\nexport function fieldGetOccurrenceNumberPairs(field, candFields) {\n // NB! TAG!=880 returns 880 fields, TAG==880 returns non-880 field\n //nvdebug(` Trying to finds pair for ${fieldToString(field)} in ${candFields.length} fields`);\n const pairs = candFields.filter(otherField => isSubfield6Pair(field, otherField));\n if (pairs.length === 0) {\n nvdebug(`NO PAIRS FOUND FOR '${fieldToString(field)}'`);\n return pairs;\n }\n //nvdebug(`${pairs.length} PAIR(S) FOUND FOR '${fieldToString(field)}'`);\n pairs.forEach(pairedField => nvdebug(` '${fieldToString(pairedField)}'`));\n return pairs;\n}\n\nexport function fieldGetOccurrenceNumbers(field) {\n let occurrenceNumbers = [];\n field.subfields?.forEach(sf => subfieldExtractOccurrenceNumber(sf));\n\n function subfieldExtractOccurrenceNumber(sf) {\n if (!isValidSubfield6(sf)) {\n return;\n }\n const occurrenceNumber = subfield6GetOccurrenceNumber(sf);\n if (occurrenceNumber === '00' || occurrenceNumbers.includes(occurrenceNumber)) {\n return;\n }\n occurrenceNumbers.push(occurrenceNumber);\n }\n return occurrenceNumbers;\n}\n\nexport function fieldsGetOccurrenceNumbers(fields) {\n let occurrenceNumbers = [];\n\n fields.forEach(f => fieldProcessOccurrenceNumbers(f));\n\n function fieldProcessOccurrenceNumbers(f) {\n const newOccurrenceNumbers = fieldGetOccurrenceNumbers(f);\n newOccurrenceNumbers.forEach(occurrenceNumber => {\n if (!occurrenceNumbers.includes(occurrenceNumber)) {\n occurrenceNumbers.push(occurrenceNumber);\n }\n\n });\n }\n return occurrenceNumbers;\n}\n\n/*\nexport function fieldGetSubfield6Pair(field, record) {\n const pairedFields = record.fields.filter(otherField => isSubfield6Pair(field, otherField));\n if (pairedFields.length !== 1) {\n return undefined;\n }\n // NB! It is theoretically possible to have multiple pairable 880 fields (one for each encoding)\n nvdebug(`fieldGetSubfield6Pair(): ${fieldToString(field)} => ${fieldToString(pairedFields[0])}`);\n return pairedFields[0];\n}\n*/\n\n/*\nexport function pairAndStringify6(field, record) {\n const pair6 = fieldGetSubfield6Pair(field, record);\n if (!pair6) {\n return fieldToNormalizedString(field);\n }\n return fieldsToNormalizedString([field, pair6]);\n}\n*/\n\n// Frequencly list for $6 subfields in 1XX/7XX fields:\n// 231115 100\n// 183832 700\n// 28773 710\n// 2047 711\n// 661 110\n// 341 111\n// 284 130\n// 63 730\n// Thus there's a real risk of ending up with, say, identical 100 vs 700 chains.\n// Semi-hackily support 1XX/7XX-version: 7XX can be deleted if corresponding 1XX exists:\n\nexport function is7XX(tag) {\n return ['700', '710', '711', '730'].includes(tag);\n}\n\n\nfunction normalizeEntryTag(tag) {\n if (tag.match(/^[17](?:00|10|11|30)$/u)) {\n return `X${tag.substring(1)}`;\n }\n return tag;\n}\n\nfunction subfieldToNormalizedString(sf, tag, targetLinkingNumber = 0, normalizeOccurrenceNumber = false, normalizeEntryTagBoolean = false) {\n // targetLinkingNumber refers to $8.\n // normalizeEntryTagBoolean refers to 1XX/7XX tag values in subfield $6 value.\n if (isValidSubfield6(sf)) { // && targetLinkingNumber === 0) {\n // 1XX/7XX (entry tag) normalization:\n const tag2 = normalizeEntryTagBoolean ? normalizeEntryTag(tag) : tag;\n\n const occurrenceNumber = normalizeOccurrenceNumber ? 'XX' : subfield6GetOccurrenceNumber(sf);\n // If we are normalizing a $8 chain, don't normalize $6 occurrence number!\n // Replace $6 occurrence number with XX:\n return ` \u2021${sf.code} ${tag2}-${occurrenceNumber}${subfield6GetTail(sf)}`;\n }\n\n if (isValidSubfield8(sf)) {\n const currLinkingNumber = getSubfield8LinkingNumber(sf); //getSubfield8Index(sf);\n if (targetLinkingNumber > 0 && currLinkingNumber === targetLinkingNumber) {\n // For $8 we should only XX the index we are looking at...\n const normVal = sf.value.replace(/^[0-9]+/u, 'XX');\n return ` \u2021${sf.code} ${normVal}`;\n }\n return ''; // Other $8 subfields are meaningless in this context\n }\n return ` ${subfieldToString(sf)}`; // `\u2021${sf.code} ${sf.value}`;\n}\n\nexport function fieldToNormalizedString(field, targetLinkingNumber = 0, normalizeOccurrenceNumber = false, normalizeEntryTagBoolean = false) {\n if ('subfields' in field) {\n const tag2 = normalizeEntryTagBoolean ? normalizeEntryTag(field.tag) : field.tag;\n return `${tag2} ${field.ind1}${field.ind2}${formatAndNormalizeSubfields(field)}`;\n }\n return `${field.tag} ${field.value}`;\n\n function formatAndNormalizeSubfields(field) {\n return field.subfields.map(sf => subfieldToNormalizedString(sf, field.tag, targetLinkingNumber, normalizeOccurrenceNumber, normalizeEntryTagBoolean)).join('');\n }\n\n}\n\n\nfunction guessTargetLinkingNumber(fields, defaultTargetLinkingNumber) {\n if (defaultTargetLinkingNumber !== 0) {\n return defaultTargetLinkingNumber;\n }\n const linkingNumbers = fieldsGetAllSubfield8LinkingNumbers(fields);\n return linkingNumbers.length === 1 ? linkingNumbers[0] : 0;\n}\n\nexport function fieldsToNormalizedString(fields, defaultTargetLinkingNumber = 0, normalizeOccurrenceNumber = false, normalizeEntryTag = false) {\n const targetLinkingNumber = guessTargetLinkingNumber(fields, defaultTargetLinkingNumber);\n\n //nvdebug(`fieldsToNormalizedString: OCC: ${normalizeOccurrenceNumber}`);\n const strings = fields.map(field => fieldToNormalizedString(field, targetLinkingNumber, normalizeOccurrenceNumber, normalizeEntryTag));\n strings.sort();\n return strings.join('\\t__SEPARATOR__\\t');\n}\n\n\n/*\n\nexport function removeField6IfNeeded(field, record, fieldsAsString) {\n const pairField = fieldGetSubfield6Pair(field, record);\n const asString = pairField ? fieldsToNormalizedString([field, pairField]) : fieldToNormalizedString(field);\n nvdebug(`SOURCE: ${asString} -- REALITY: ${fieldToString(field)}`);\n const tmp = pairField ? fieldToString(pairField) : 'HUTI';\n nvdebug(`PAIR: ${tmp}`);\n nvdebug(`BASE:\\n ${fieldsAsString.join('\\n ')}`);\n if (!fieldsAsString.includes(asString)) {\n return;\n }\n nvdebug(`Duplicate $6 removal: ${fieldToString(field)}`);\n record.removeField(field);\n\n if (pairField === undefined) {\n return;\n }\n nvdebug(`Duplicate $6 removal (pair): ${fieldToString(pairField)}`);\n record.removeField(pairField);\n}\n*/\n\nfunction getFirstField(record, fields) {\n const fieldsAsStrings = fields.map(field => fieldToString(field));\n //record.fields.forEach((field, i) => nvdebug(`${i}:\\t${fieldToString(field)}`));\n //nvdebug(`getFirstField: ${fieldsAsStrings.join('\\t')}`);\n const i = record.fields.findIndex(field => fieldsAsStrings.includes(fieldToString(field)));\n if (i > -1) {\n const field = record.fields[i];\n //nvdebug(`1st F: ${i + 1}/${record.fields.length} ${fieldToString(field)}`);\n return field;\n }\n return undefined;\n}\n\nfunction isRelevantSubfield6Chain(fields) {\n if (fields.length < 2) { // 1 non-880-field and 1+ 880 fields\n return false;\n }\n const non880 = fields.filter(f => f.tag !== '880');\n if (non880.length !== 1) {\n return false;\n }\n\n const linkingNumbers = fieldsGetAllSubfield8LinkingNumbers(fields);\n if (linkingNumbers.length !== 0) {\n return false;\n }\n\n return fields.every(f => fieldHasSubfield(f, '6'));\n}\n\nexport function fieldIsFirstFieldInChain(field, chain, record) {\n // Interpretation of first: position of field in record (however, we might have a duplicate field. See tests...)\n const firstField = getFirstField(record, chain);\n if (firstField) {\n return fieldToString(field) === fieldToString(firstField);\n }\n return false;\n\n}\n\n\nexport function getAllLinkedSubfield6Fields(field, record) {\n const fields = get6s(field, record);\n const moreFields = add8s(fields, record);\n\n // Currently we don't handle fields with more than one $6 and/or $8 subfield.\n if (moreFields.length > fields.length) {\n return []; // Don't fix!\n }\n return moreFields;\n}\n\nexport function isFirstLinkedSubfield6Field(field, record) {\n if (!field.subfields) { // Is not a datafield\n return false;\n }\n const chain = getAllLinkedSubfield6Fields(field, record);\n if (!isRelevantSubfield6Chain(chain)) {\n //nvdebug(`Rejected 6: ${fieldsToString(chain)}`);\n return false;\n }\n\n return fieldIsFirstFieldInChain(field, chain, record);\n}\n\nexport function recordGetSubfield6ChainHeads(record) {\n return record.fields.filter(field => isFirstLinkedSubfield6Field(field, record));\n}\n\nexport function recordGetMaxSubfield6OccurrenceNumberAsInteger(record) {\n if (record.fields.length === 0) {\n return 0;\n }\n // Should we cache the value here?\n const vals = record.fields.map((field) => fieldGetMaxSubfield6OccurrenceNumberAsInteger(field));\n return Math.max(...vals);\n}\n\nexport function get6s(field, candidateFields) { // NB! Convert field to fields!!!\n // Get all fields with given occurrence number\n const sixes = field.subfields.filter(sf => isValidSubfield6(sf));\n\n if (sixes.length === 0) {\n return [field];\n }\n //nvdebug(`SIXES: ${sixes.length}`);\n const occurrenceNumbers = sixes.map(sf => subfield6GetOccurrenceNumber(sf)).filter(value => value !== undefined && value !== '00');\n //nvdebug(occurrenceNumbers.join(' -- '));\n\n const relevantFields = candidateFields.filter(f => occurrenceNumbers.some(o => fieldHasOccurrenceNumber(f, o)));\n //nvdebug(`${fieldToString(field)}: $6-RELFIELDS FOUND: ${relevantFields.length}...`);\n //relevantFields.forEach(f => nvdebug(fieldToString(f)));\n return relevantFields;\n}\n\nexport function resetSubfield6Tag(subfield, tag) {\n if (!isValidSubfield6(subfield)) {\n return;\n }\n // NB! mainly for 1XX<->7XX transfers\n const newValue = `${tag}-${subfield.value.substring(4)}`;\n //nvdebug(`Set subfield $6 value from ${subfieldToString(subfield)} to ${newValue}`, debugDev);\n subfield.value = newValue;\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["//import createDebugLogger from 'debug';\n// const debug = createDebugLogger('@natlibfi/marc-record-validator-melinda/subfield6Utils');\n\nimport {add8s, fieldsGetAllSubfield8LinkingNumbers, getSubfield8LinkingNumber, isValidSubfield8} from './subfield8Utils.js';\nimport {fieldHasSubfield, fieldToString, /* fieldsToString, */ nvdebug, subfieldToString} from './utils.js';\n\n//const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:subfield6Utils');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\n// NB! Subfield 6 is non-repeatable and it should always comes first!\n// NB! Index size should always be 2 (preceding 0 required for 01..09) However, support for 100+ was added on 2023-02-27.\n// NB! Index value '00' are left as they are (is not paired/indexed/whatever.\nconst sf6Regexp = /^[0-9][0-9][0-9]-(?:[0-9][0-9]|[1-9][0-9]+)(?:[^0-9].*)?$/u;\n\nexport function isValidSubfield6(subfield) {\n if (subfield.code !== '6') {\n return false;\n }\n return subfield.value.match(sf6Regexp);\n}\n\nexport function subfield6GetTag(subfield) {\n if (isValidSubfield6(subfield)) {\n return subfield.value.substring(0, 3);\n }\n return undefined;\n}\n\nexport function subfield6GetOccurrenceNumber(subfield) {\n if (isValidSubfield6(subfield)) {\n // Skip \"TAG-\" prefix. 2023-02-20: removed 2-digit requirement from here...\n return subfield.value.substring(4).replace(/\\D.*$/u, '');\n }\n return undefined;\n}\n\nexport function subfield6GetOccurrenceNumberAsInteger(subfield) {\n const index = subfield6GetOccurrenceNumber(subfield);\n if (index === undefined || index === '00') {\n return 0;\n }\n const result = parseInt(index, 10);\n //nvdebug(`SF6: ${subfield.value} => ${index} => ${result}`, debug);\n return result;\n}\n\nexport function subfield6ResetOccurrenceNumber(subfield, occurrenceNumber) {\n if (!isValidSubfield6(subfield)) {\n return;\n }\n const occurrenceNumberAsString = typeof occurrenceNumber === 'number' ? intToOccurrenceNumberString(occurrenceNumber) : occurrenceNumber;\n\n const newValue = subfield.value.substring(0, 4) + occurrenceNumberAsString + subfield6GetTail(subfield);\n //nvdebug(`Set subfield $6 value from ${subfieldToString(subfield)} to ${newValue}`);\n subfield.value = newValue;\n}\n\n\nfunction subfield6GetTail(subfield) {\n if (isValidSubfield6(subfield)) {\n // Skip \"TAG-\" prefix. 2023-02-20: removed 2-digit requirement from here...\n return subfield.value.replace(/^\\d+-\\d+/u, '');\n }\n return '';\n}\n\nexport function subfield6HasWantedTagAndOccurrenceNumber(subfield, tagAndOccurrenceNumber) {\n if (subfield.code !== '6') {\n return false;\n }\n // We could also use generic code and go getTag()+'-'+getIndex() instead of regexp...\n const key = subfield.value.replace(/^([0-9][0-9][0-9]-[0-9][0-9]+).*$/u, '$1');\n //nvdebug(` Compare '${key}' vs '${tagAndOccurrenceNumber}'`);\n return key === tagAndOccurrenceNumber;\n}\n\n// <= SUBFIELD, FIELD =>\n\nexport function fieldGetUnambiguousTag(field) {\n const tags = field.subfields.filter(sf => subfield6GetTag(sf));\n if (tags.length === 1) {\n return subfield6GetTag(tags[0]);\n }\n return undefined;\n}\n\nexport function fieldGetUnambiguousOccurrenceNumber(field) {\n const occurrenceNumbers = field.subfields.filter(sf => subfield6GetOccurrenceNumber(sf));\n if (occurrenceNumbers.length === 1) {\n return subfield6GetOccurrenceNumber(occurrenceNumbers[0]);\n }\n return undefined;\n}\n\nexport function fieldHasOccurrenceNumber(field, occurrenceNumber) {\n //nvdebug(`${occurrenceNumber} vs ${fieldToString(field)}`);\n return field.subfields && field.subfields.some(sf => subfield6GetOccurrenceNumber(sf) === occurrenceNumber);\n}\n\nexport function fieldResetOccurrenceNumber(field, newOccurrenceNumber, oldOccurrenceNumber = undefined) {\n field.subfields.forEach(subfield => innerReset(subfield));\n\n function innerReset(subfield) {\n // (Optional) Check that this is really the occurrence number we wan't to reseot\n if (oldOccurrenceNumber !== undefined) {\n const currOccurrenceNumber = subfield6GetOccurrenceNumber(subfield);\n if (currOccurrenceNumber !== oldOccurrenceNumber) {\n return;\n }\n }\n subfield6ResetOccurrenceNumber(subfield, newOccurrenceNumber);\n }\n}\n\nexport function intToOccurrenceNumberString(i) {\n return i < 10 ? `0${i}` : `${i}`;\n}\n\nexport function fieldGetMaxSubfield6OccurrenceNumberAsInteger(field) {\n // used by reducer!\n //nvdebug(`Checking subfields $6 from ${JSON.stringify(field)}`);\n const sf6s = field.subfields ? field.subfields.filter(subfield => isValidSubfield6(subfield)) : [];\n if (sf6s.length === 0) {\n return 0;\n }\n // There should always be one, but here we check every subfield.\n //nvdebug(`Got ${field.subfields} $6-subfield(s) from ${JSON.stringify(field)}`, debug);\n const vals = sf6s.map(sf => subfield6GetOccurrenceNumberAsInteger(sf));\n return Math.max(...vals);\n}\n\nexport function fieldHasWantedTagAndOccurrenceNumber(field, tagAndOccurrenceNumber) {\n return field.subfields && field.subfields.some(sf => subfield6HasWantedTagAndOccurrenceNumber(sf, tagAndOccurrenceNumber));\n}\n\n\n/*\nexport function getFieldsWithGivenOccurrenceNumberSubfield6(record, occurrenceNumberAsString) {\n const record.fields.filter(field => field\n\n function fieldHasIndex(field, index) {\n if (!field.subfields) {\n return false;\n }\n return field.subfields.find(sf => isValidSubfield6(sf) && subfieldGetOccurrenceNumber6(sf) === index);\n }\n}\n*/\n\n\nexport function fieldHasValidSubfield6(field) {\n return field.subfields && field.subfields.some(sf => isValidSubfield6(sf));\n}\n\nexport function isSubfield6Pair(field, otherField) {\n // No need to log this:\n //nvdebug(`LOOK for $6-pair:\\n ${fieldToString(field)}\\n ${fieldToString(otherField)}`);\n if (!fieldHasValidSubfield6(field) || !fieldHasValidSubfield6(otherField)) {\n return false;\n }\n\n if (!tagsArePairable6(field.tag, otherField.tag)) {\n //nvdebug(` FAILED. REASON: TAGS NOT PAIRABLE!`);\n return false;\n }\n\n\n const fieldIndex = fieldGetUnambiguousOccurrenceNumber(field);\n if (fieldIndex === undefined || fieldIndex === '00') {\n //nvdebug(` FAILED. REASON: NO INDEX FOUND`);\n return false;\n }\n\n const otherFieldIndex = fieldGetUnambiguousOccurrenceNumber(otherField);\n\n\n if (fieldIndex !== otherFieldIndex) {\n //nvdebug(` FAILURE: INDEXES: ${fieldIndex} vs ${otherFieldIndex}`);\n return false;\n }\n\n if (fieldGetUnambiguousTag(field) !== otherField.tag || field.tag !== fieldGetUnambiguousTag(otherField)) {\n //nvdebug(` FAILURE: TAG vs $6 TAG`);\n return false;\n }\n return true;\n\n function tagsArePairable6(tag1, tag2) {\n // How to do XOR operation in one line? Well, this is probably more readable...\n if (tag1 === '880' && tag2 === '880') {\n return false;\n }\n if (tag1 !== '880' && tag2 !== '880') {\n return false;\n }\n return true;\n }\n}\n\n\nfunction subfieldSevenToOneOccurrenceNumber(subfield) {\n if (subfield.code !== '6' || subfield.value.substring(0, 1) !== '7') {\n return;\n }\n subfield.value = `1${subfield.value.substring(1)}`;\n}\n\nexport function fieldSevenToOneOccurrenceNumber(field) {\n if (field.tag !== '880') {\n return;\n }\n field.subfields.forEach(sf => subfieldSevenToOneOccurrenceNumber(sf));\n}\n\n\nexport function fieldGetOccurrenceNumberPairs(field, candFields) {\n // NB! TAG!=880 returns 880 fields, TAG==880 returns non-880 field\n //nvdebug(` Trying to finds pair for ${fieldToString(field)} in ${candFields.length} fields`);\n const pairs = candFields.filter(otherField => isSubfield6Pair(field, otherField));\n if (pairs.length === 0) {\n //nvdebug(`NO PAIRS FOUND FOR '${fieldToString(field)}'`);\n return pairs;\n }\n //nvdebug(`${pairs.length} PAIR(S) FOUND FOR '${fieldToString(field)}'`);\n pairs.forEach(pairedField => nvdebug(` '${fieldToString(pairedField)}'`));\n return pairs;\n}\n\nexport function fieldGetOccurrenceNumbers(field) {\n let occurrenceNumbers = [];\n field.subfields?.forEach(sf => subfieldExtractOccurrenceNumber(sf));\n\n function subfieldExtractOccurrenceNumber(sf) {\n if (!isValidSubfield6(sf)) {\n return;\n }\n const occurrenceNumber = subfield6GetOccurrenceNumber(sf);\n if (occurrenceNumber === '00' || occurrenceNumbers.includes(occurrenceNumber)) {\n return;\n }\n occurrenceNumbers.push(occurrenceNumber);\n }\n return occurrenceNumbers;\n}\n\nexport function fieldsGetOccurrenceNumbers(fields) {\n let occurrenceNumbers = [];\n\n fields.forEach(f => fieldProcessOccurrenceNumbers(f));\n\n function fieldProcessOccurrenceNumbers(f) {\n const newOccurrenceNumbers = fieldGetOccurrenceNumbers(f);\n newOccurrenceNumbers.forEach(occurrenceNumber => {\n if (!occurrenceNumbers.includes(occurrenceNumber)) {\n occurrenceNumbers.push(occurrenceNumber);\n }\n\n });\n }\n return occurrenceNumbers;\n}\n\n/*\nexport function fieldGetSubfield6Pair(field, record) {\n const pairedFields = record.fields.filter(otherField => isSubfield6Pair(field, otherField));\n if (pairedFields.length !== 1) {\n return undefined;\n }\n // NB! It is theoretically possible to have multiple pairable 880 fields (one for each encoding)\n nvdebug(`fieldGetSubfield6Pair(): ${fieldToString(field)} => ${fieldToString(pairedFields[0])}`);\n return pairedFields[0];\n}\n*/\n\n/*\nexport function pairAndStringify6(field, record) {\n const pair6 = fieldGetSubfield6Pair(field, record);\n if (!pair6) {\n return fieldToNormalizedString(field);\n }\n return fieldsToNormalizedString([field, pair6]);\n}\n*/\n\n// Frequencly list for $6 subfields in 1XX/7XX fields:\n// 231115 100\n// 183832 700\n// 28773 710\n// 2047 711\n// 661 110\n// 341 111\n// 284 130\n// 63 730\n// Thus there's a real risk of ending up with, say, identical 100 vs 700 chains.\n// Semi-hackily support 1XX/7XX-version: 7XX can be deleted if corresponding 1XX exists:\n\nexport function is7XX(tag) {\n return ['700', '710', '711', '730'].includes(tag);\n}\n\n\nfunction normalizeEntryTag(tag) {\n if (tag.match(/^[17](?:00|10|11|30)$/u)) {\n return `X${tag.substring(1)}`;\n }\n return tag;\n}\n\nfunction subfieldToNormalizedString(sf, tag, targetLinkingNumber = 0, normalizeOccurrenceNumber = false, normalizeEntryTagBoolean = false) {\n // targetLinkingNumber refers to $8.\n // normalizeEntryTagBoolean refers to 1XX/7XX tag values in subfield $6 value.\n if (isValidSubfield6(sf)) { // && targetLinkingNumber === 0) {\n // 1XX/7XX (entry tag) normalization:\n const tag2 = normalizeEntryTagBoolean ? normalizeEntryTag(tag) : tag;\n\n const occurrenceNumber = normalizeOccurrenceNumber ? 'XX' : subfield6GetOccurrenceNumber(sf);\n // If we are normalizing a $8 chain, don't normalize $6 occurrence number!\n // Replace $6 occurrence number with XX:\n return ` \u2021${sf.code} ${tag2}-${occurrenceNumber}${subfield6GetTail(sf)}`;\n }\n\n if (isValidSubfield8(sf)) {\n const currLinkingNumber = getSubfield8LinkingNumber(sf); //getSubfield8Index(sf);\n if (targetLinkingNumber > 0 && currLinkingNumber === targetLinkingNumber) {\n // For $8 we should only XX the index we are looking at...\n const normVal = sf.value.replace(/^[0-9]+/u, 'XX');\n return ` \u2021${sf.code} ${normVal}`;\n }\n return ''; // Other $8 subfields are meaningless in this context\n }\n return ` ${subfieldToString(sf)}`; // `\u2021${sf.code} ${sf.value}`;\n}\n\nexport function fieldToNormalizedString(field, targetLinkingNumber = 0, normalizeOccurrenceNumber = false, normalizeEntryTagBoolean = false) {\n if ('subfields' in field) {\n const tag2 = normalizeEntryTagBoolean ? normalizeEntryTag(field.tag) : field.tag;\n return `${tag2} ${field.ind1}${field.ind2}${formatAndNormalizeSubfields(field)}`;\n }\n return `${field.tag} ${field.value}`;\n\n function formatAndNormalizeSubfields(field) {\n return field.subfields.map(sf => subfieldToNormalizedString(sf, field.tag, targetLinkingNumber, normalizeOccurrenceNumber, normalizeEntryTagBoolean)).join('');\n }\n\n}\n\n\nfunction guessTargetLinkingNumber(fields, defaultTargetLinkingNumber) {\n if (defaultTargetLinkingNumber !== 0) {\n return defaultTargetLinkingNumber;\n }\n const linkingNumbers = fieldsGetAllSubfield8LinkingNumbers(fields);\n return linkingNumbers.length === 1 ? linkingNumbers[0] : 0;\n}\n\nexport function fieldsToNormalizedString(fields, defaultTargetLinkingNumber = 0, normalizeOccurrenceNumber = false, normalizeEntryTag = false) {\n const targetLinkingNumber = guessTargetLinkingNumber(fields, defaultTargetLinkingNumber);\n\n //nvdebug(`fieldsToNormalizedString: OCC: ${normalizeOccurrenceNumber}`);\n const strings = fields.map(field => fieldToNormalizedString(field, targetLinkingNumber, normalizeOccurrenceNumber, normalizeEntryTag));\n strings.sort();\n return strings.join('\\t__SEPARATOR__\\t');\n}\n\n\n/*\n\nexport function removeField6IfNeeded(field, record, fieldsAsString) {\n const pairField = fieldGetSubfield6Pair(field, record);\n const asString = pairField ? fieldsToNormalizedString([field, pairField]) : fieldToNormalizedString(field);\n nvdebug(`SOURCE: ${asString} -- REALITY: ${fieldToString(field)}`);\n const tmp = pairField ? fieldToString(pairField) : 'HUTI';\n nvdebug(`PAIR: ${tmp}`);\n nvdebug(`BASE:\\n ${fieldsAsString.join('\\n ')}`);\n if (!fieldsAsString.includes(asString)) {\n return;\n }\n nvdebug(`Duplicate $6 removal: ${fieldToString(field)}`);\n record.removeField(field);\n\n if (pairField === undefined) {\n return;\n }\n nvdebug(`Duplicate $6 removal (pair): ${fieldToString(pairField)}`);\n record.removeField(pairField);\n}\n*/\n\nfunction getFirstField(record, fields) {\n const fieldsAsStrings = fields.map(field => fieldToString(field));\n //record.fields.forEach((field, i) => nvdebug(`${i}:\\t${fieldToString(field)}`));\n //nvdebug(`getFirstField: ${fieldsAsStrings.join('\\t')}`);\n const i = record.fields.findIndex(field => fieldsAsStrings.includes(fieldToString(field)));\n if (i > -1) {\n const field = record.fields[i];\n //nvdebug(`1st F: ${i + 1}/${record.fields.length} ${fieldToString(field)}`);\n return field;\n }\n return undefined;\n}\n\nfunction isRelevantSubfield6Chain(fields) {\n if (fields.length < 2) { // 1 non-880-field and 1+ 880 fields\n return false;\n }\n const non880 = fields.filter(f => f.tag !== '880');\n if (non880.length !== 1) {\n return false;\n }\n\n const linkingNumbers = fieldsGetAllSubfield8LinkingNumbers(fields);\n if (linkingNumbers.length !== 0) {\n return false;\n }\n\n return fields.every(f => fieldHasSubfield(f, '6'));\n}\n\nexport function fieldIsFirstFieldInChain(field, chain, record) {\n // Interpretation of first: position of field in record (however, we might have a duplicate field. See tests...)\n const firstField = getFirstField(record, chain);\n if (firstField) {\n return fieldToString(field) === fieldToString(firstField);\n }\n return false;\n\n}\n\n\nexport function getAllLinkedSubfield6Fields(field, record) {\n const fields = get6s(field, record);\n const moreFields = add8s(fields, record);\n\n // Currently we don't handle fields with more than one $6 and/or $8 subfield.\n if (moreFields.length > fields.length) {\n return []; // Don't fix!\n }\n return moreFields;\n}\n\nexport function isFirstLinkedSubfield6Field(field, record) {\n if (!field.subfields) { // Is not a datafield\n return false;\n }\n const chain = getAllLinkedSubfield6Fields(field, record);\n if (!isRelevantSubfield6Chain(chain)) {\n //nvdebug(`Rejected 6: ${fieldsToString(chain)}`);\n return false;\n }\n\n return fieldIsFirstFieldInChain(field, chain, record);\n}\n\nexport function recordGetSubfield6ChainHeads(record) {\n return record.fields.filter(field => isFirstLinkedSubfield6Field(field, record));\n}\n\nexport function recordGetMaxSubfield6OccurrenceNumberAsInteger(record) {\n if (record.fields.length === 0) {\n return 0;\n }\n // Should we cache the value here?\n const vals = record.fields.map((field) => fieldGetMaxSubfield6OccurrenceNumberAsInteger(field));\n return Math.max(...vals);\n}\n\nexport function get6s(field, candidateFields) { // NB! Convert field to fields!!!\n // Get all fields with given occurrence number\n const sixes = field.subfields.filter(sf => isValidSubfield6(sf));\n\n if (sixes.length === 0) {\n return [field];\n }\n //nvdebug(`SIXES: ${sixes.length}`);\n const occurrenceNumbers = sixes.map(sf => subfield6GetOccurrenceNumber(sf)).filter(value => value !== undefined && value !== '00');\n //nvdebug(occurrenceNumbers.join(' -- '));\n\n const relevantFields = candidateFields.filter(f => occurrenceNumbers.some(o => fieldHasOccurrenceNumber(f, o)));\n //nvdebug(`${fieldToString(field)}: $6-RELFIELDS FOUND: ${relevantFields.length}...`);\n //relevantFields.forEach(f => nvdebug(fieldToString(f)));\n return relevantFields;\n}\n\nexport function resetSubfield6Tag(subfield, tag) {\n if (!isValidSubfield6(subfield)) {\n return;\n }\n // NB! mainly for 1XX<->7XX transfers\n const newValue = `${tag}-${subfield.value.substring(4)}`;\n //nvdebug(`Set subfield $6 value from ${subfieldToString(subfield)} to ${newValue}`, debugDev);\n subfield.value = newValue;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["field", "normalizeEntryTag"]
|
|
7
7
|
}
|
package/dist/subfield8Utils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { fieldToString, nvdebug } from "./utils.js";
|
|
2
1
|
const sf8Regexp = /^([1-9][0-9]*)(?:\.[0-9]+)?(?:\\[acprux])?$/u;
|
|
3
2
|
export function isValidSubfield8(subfield) {
|
|
4
3
|
if (subfield.code !== "8") {
|
|
@@ -41,7 +40,6 @@ export function fieldsGetAllSubfield8LinkingNumbers(fields) {
|
|
|
41
40
|
field.subfields.forEach((sf) => {
|
|
42
41
|
const linkingNumber = getSubfield8LinkingNumber(sf);
|
|
43
42
|
if (linkingNumber > 0 && !subfield8LinkingNumbers.includes(linkingNumber)) {
|
|
44
|
-
nvdebug(` LINK8: Add subfield $8 ${linkingNumber} to seen values list`);
|
|
45
43
|
subfield8LinkingNumbers.push(linkingNumber);
|
|
46
44
|
}
|
|
47
45
|
});
|
|
@@ -56,14 +54,11 @@ export function add8s(fields, record) {
|
|
|
56
54
|
if (linkingNumbers.length === 0) {
|
|
57
55
|
return fields;
|
|
58
56
|
}
|
|
59
|
-
nvdebug(`Linking number(s): ${linkingNumbers.join(", ")}`);
|
|
60
57
|
linkingNumbers.forEach((number) => collectLinkingNumberFields(number));
|
|
61
|
-
fields.forEach((f) => nvdebug(`AFTER ADDING 8s: '${fieldToString(f)}'`));
|
|
62
58
|
return fields;
|
|
63
59
|
function collectLinkingNumberFields(linkingNumber) {
|
|
64
60
|
fields = fields.filter((f) => !fieldHasLinkingNumber(f, linkingNumber));
|
|
65
61
|
const addableFields = record.fields.filter((f) => fieldHasLinkingNumber(f, linkingNumber));
|
|
66
|
-
addableFields.forEach((f) => nvdebug(`(RE-?)ADD ${fieldToString(f)}`));
|
|
67
62
|
fields = fields.concat(addableFields);
|
|
68
63
|
}
|
|
69
64
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/subfield8Utils.js"],
|
|
4
|
-
"sourcesContent": ["// import createDebugLogger from 'debug';\n// const debug = createDebugLogger('@natlibfi/marc-record-validator-melinda/subfield8Utils');\n\
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["// import createDebugLogger from 'debug';\n// const debug = createDebugLogger('@natlibfi/marc-record-validator-melinda/subfield8Utils');\n\n// import {fieldToString, nvdebug} from './utils.js';\n\nconst sf8Regexp = /^([1-9][0-9]*)(?:\\.[0-9]+)?(?:\\\\[acprux])?$/u;\n\nexport function isValidSubfield8(subfield) {\n if (subfield.code !== '8') {\n return false;\n }\n\n //nvdebug(` IS VALID $8? '${subfieldToString(subfield)}'`);\n const match = subfield.value.match(sf8Regexp);\n //nvdebug(` IS VALID $8? '${subfieldToString(subfield)}' vs ${match.length}}`);\n return match && match.length > 0;\n}\n\nexport function getSubfield8Value(subfield) {\n if (!isValidSubfield8(subfield)) {\n return undefined;\n }\n return subfield.value;\n}\n\nexport function getSubfield8LinkingNumber(subfield) {\n const value = getSubfield8Value(subfield);\n if (value === undefined) {\n return 0;\n }\n return parseInt(value, 10);\n}\n\n\nexport function fieldHasLinkingNumber(field, linkingNumber) {\n if (!field.subfields) {\n return false;\n }\n return field.subfields.some(sf => getSubfield8LinkingNumber(sf) === linkingNumber);\n}\n\nexport function recordGetFieldsWithSubfield8LinkingNumber(record, linkingNumber) {\n if (linkingNumber < 1) {\n return;\n }\n return record.fields.filter(field => fieldHasLinkingNumber(field, linkingNumber));\n}\n\n\nexport function fieldsGetAllSubfield8LinkingNumbers(fields) {\n let subfield8LinkingNumbers = [];\n fields.forEach(field => {\n if (!field.subfields) {\n return;\n }\n field.subfields.forEach(sf => {\n const linkingNumber = getSubfield8LinkingNumber(sf);\n if (linkingNumber > 0 && !subfield8LinkingNumbers.includes(linkingNumber)) {\n //nvdebug(` LINK8: Add subfield \\$8 ${linkingNumber} to seen values list`);\n subfield8LinkingNumbers.push(linkingNumber);\n }\n });\n });\n\n return subfield8LinkingNumbers;\n}\n\nexport function recordGetAllSubfield8LinkingNumbers(record) {\n return fieldsGetAllSubfield8LinkingNumbers(record.fields);\n}\n\n\nexport function add8s(fields, record) {\n const linkingNumbers = fieldsGetAllSubfield8LinkingNumbers(fields);\n if (linkingNumbers.length === 0) {\n return fields;\n }\n\n //nvdebug(`Linking number(s): ${linkingNumbers.join(', ')}`);\n linkingNumbers.forEach(number => collectLinkingNumberFields(number));\n\n //fields.forEach(f => nvdebug(`AFTER ADDING 8s: '${fieldToString(f)}'`));\n\n return fields;\n\n function collectLinkingNumberFields(linkingNumber) {\n // Remove existing hits (to avoid field repetition):\n fields = fields.filter(f => !fieldHasLinkingNumber(f, linkingNumber));\n // Add them and their \"sisters\" back:\n const addableFields = record.fields.filter(f => fieldHasLinkingNumber(f, linkingNumber));\n //addableFields.forEach(f => nvdebug(`(RE-?)ADD ${fieldToString(f)}`));\n fields = fields.concat(addableFields);\n\n }\n}\n\nexport function fieldHasValidSubfield8(field) {\n return field.subfields && field.subfields.some(sf => isValidSubfield8(sf));\n}\n"],
|
|
5
|
+
"mappings": "AAKA,MAAM,YAAY;AAEX,gBAAS,iBAAiB,UAAU;AACzC,MAAI,SAAS,SAAS,KAAK;AACzB,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,SAAS,MAAM,MAAM,SAAS;AAE5C,SAAO,SAAS,MAAM,SAAS;AACjC;AAEO,gBAAS,kBAAkB,UAAU;AAC1C,MAAI,CAAC,iBAAiB,QAAQ,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,SAAO,SAAS;AAClB;AAEO,gBAAS,0BAA0B,UAAU;AAClD,QAAM,QAAQ,kBAAkB,QAAQ;AACxC,MAAI,UAAU,QAAW;AACvB,WAAO;AAAA,EACT;AACA,SAAO,SAAS,OAAO,EAAE;AAC3B;AAGO,gBAAS,sBAAsB,OAAO,eAAe;AAC1D,MAAI,CAAC,MAAM,WAAW;AACpB,WAAO;AAAA,EACT;AACA,SAAO,MAAM,UAAU,KAAK,QAAM,0BAA0B,EAAE,MAAM,aAAa;AACnF;AAEO,gBAAS,0CAA0C,QAAQ,eAAe;AAC/E,MAAI,gBAAgB,GAAG;AACrB;AAAA,EACF;AACA,SAAO,OAAO,OAAO,OAAO,WAAS,sBAAsB,OAAO,aAAa,CAAC;AAClF;AAGO,gBAAS,oCAAoC,QAAQ;AAC1D,MAAI,0BAA0B,CAAC;AAC/B,SAAO,QAAQ,WAAS;AACtB,QAAI,CAAC,MAAM,WAAW;AACpB;AAAA,IACF;AACA,UAAM,UAAU,QAAQ,QAAM;AAC5B,YAAM,gBAAgB,0BAA0B,EAAE;AAClD,UAAI,gBAAgB,KAAK,CAAC,wBAAwB,SAAS,aAAa,GAAG;AAEzE,gCAAwB,KAAK,aAAa;AAAA,MAC5C;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,SAAO;AACT;AAEO,gBAAS,oCAAoC,QAAQ;AAC1D,SAAO,oCAAoC,OAAO,MAAM;AAC1D;AAGO,gBAAS,MAAM,QAAQ,QAAQ;AACpC,QAAM,iBAAiB,oCAAoC,MAAM;AACjE,MAAI,eAAe,WAAW,GAAG;AAC/B,WAAO;AAAA,EACT;AAGA,iBAAe,QAAQ,YAAU,2BAA2B,MAAM,CAAC;AAInE,SAAO;AAEP,WAAS,2BAA2B,eAAe;AAEjD,aAAS,OAAO,OAAO,OAAK,CAAC,sBAAsB,GAAG,aAAa,CAAC;AAEpE,UAAM,gBAAgB,OAAO,OAAO,OAAO,OAAK,sBAAsB,GAAG,aAAa,CAAC;AAEvF,aAAS,OAAO,OAAO,aAAa;AAAA,EAEtC;AACF;AAEO,gBAAS,uBAAuB,OAAO;AAC5C,SAAO,MAAM,aAAa,MAAM,UAAU,KAAK,QAAM,iBAAiB,EAAE,CAAC;AAC3E;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/utils.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import createDebugLogger from "debug";
|
|
2
|
+
import { melindaFieldSpecs } from "./melindaCustomMergeFields.js";
|
|
3
|
+
import { isDataProvenanceSubfieldCode } from "./dataProvenanceUtils.js";
|
|
2
4
|
const debug = createDebugLogger("@natlibfi/melinda-marc-record-merge-reducers:utils");
|
|
3
5
|
const debugDev = debug.extend("dev");
|
|
4
|
-
import { melindaFieldSpecs } from "./melindaCustomMergeFields.js";
|
|
5
6
|
export function isElectronicMaterial(record) {
|
|
6
7
|
const f337s = record.get("337");
|
|
7
8
|
return f337s.length > 0 && f337s.some((f) => fieldHasSubfield(f, "b", "c") && fieldHasSubfield(f, "2", "rdamedia"));
|
|
@@ -77,12 +78,29 @@ export function fieldsToString(fields) {
|
|
|
77
78
|
export function nvdebugFieldArray(fields, prefix = " ", func = void 0) {
|
|
78
79
|
fields.forEach((field) => nvdebug(`${prefix}${fieldToString(field)}`, func));
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
if (["0", "1", "2", "
|
|
81
|
+
function isControlSubfieldCode(subfieldCode, tag = void 0) {
|
|
82
|
+
if (["0", "1", "2", "5", "6", "8", "w"].includes(subfieldCode)) {
|
|
82
83
|
return true;
|
|
83
84
|
}
|
|
85
|
+
if (tag && subfieldCode === "7") {
|
|
86
|
+
if (tag.match(/^7[678]/u) || ["800", "810", "811", "830"].includes(tag)) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
84
90
|
return false;
|
|
85
91
|
}
|
|
92
|
+
export function isContentSubfieldCode(subfieldCode, tag = void 0) {
|
|
93
|
+
if (isControlSubfieldCode(subfieldCode, tag)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
if (tag && isDataProvenanceSubfieldCode(subfieldCode, tag)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
if (["2", "3", "4", "7", "9"].includes(subfieldCode)) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
86
104
|
export function getCatalogingLanguage(record, defaultCatalogingLanguage = void 0) {
|
|
87
105
|
const [field040] = record.get(/^040$/u);
|
|
88
106
|
if (!field040) {
|
|
@@ -177,4 +195,12 @@ export function subfieldArraysContainSameData(arr1, arr2) {
|
|
|
177
195
|
}
|
|
178
196
|
return arr2.every((sf2) => arr1.some((sf) => subfieldsAreIdentical(sf, sf2)));
|
|
179
197
|
}
|
|
198
|
+
export function tagIsRepeatable(tag) {
|
|
199
|
+
const fieldSpecs = melindaFieldSpecs.fields.filter((field) => field.tag === tag);
|
|
200
|
+
if (fieldSpecs.length !== 1) {
|
|
201
|
+
debugDev(` WARNING! Getting field ${tag} data failed! Default to repeatable field.`);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
return fieldSpecs[0].repeatable;
|
|
205
|
+
}
|
|
180
206
|
//# sourceMappingURL=utils.js.map
|