@natlibfi/marc-record-validators-melinda 12.0.0-alpha.2 → 12.0.0-alpha.4

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.
@@ -99,7 +99,7 @@ function extractAllPrintData(relevantFields) {
99
99
  ;
100
100
  return allPrintData.filter((p) => p !== void 0);
101
101
  }
102
- export function mergeLisapainokset(record) {
102
+ function mergeLisapainokset(record) {
103
103
  const relevantFields = getRelevantFields(record);
104
104
  if (relevantFields.length < 2) {
105
105
  return;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/mergeField500Lisapainokset.js"],
4
- "sourcesContent": ["export default function () {\n\n return {\n description: 'Merge 500 $a Lis\u00E4painokset fields',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n mergeLisapainokset(record);\n return res;\n }\n\n function validate(record) {\n const relevantFields = getRelevantFields(record);\n if (relevantFields.length < 2) {\n return {message: [], 'valid': true}; // No action required\n }\n\n const printData = extractAllPrintData(relevantFields);\n if (printData.length === 0) {\n return {message: ['There are issues, but the fixer can not fix them!'], 'valid': false}; // No action required\n }\n\n return {message: [`Fixer can merge ${relevantFields.length} 500 $a Lis\u00E4painokset fields into one`], 'valid': false};\n }\n}\n\n\nfunction getRelevantFields(record) {\n return record.fields.filter(field => validLisapainosField(field));\n}\n\nfunction validLisapainosField(field) {\n // We are only interested in field 500 with a lone $a subfield.\n // Especially $9 FENNI<KEEP> should not be merged!\n if (field.tag !== '500' || field.subfields.length !== 1 || field.subfields[0].code !== 'a') {\n return false;\n }\n return field.subfields[0].value.match(/^(?:Lis\u00E4painokset|Lis\u00E4painos): (?:[1-9][0-9]*\\. (?:p\\.|painos|uppl\\.) [0-9]+\\.)(?: - [1-9][0-9]*\\. (?:p\\.|painos|uppl\\.) \\[?[0-9]+\\]?\\.)*$/u);\n}\n\nfunction fieldToPrintsString(field) {\n // Could this just be something on the lines of s/^\\S+ // ?\n return field.subfields[0].value.replace(/^(?:Lis\u00E4painokset|Lis\u00E4painos): /u, '').replace(/\\.$/u, '');\n}\n\nconst printPreference = ['painos', 'p.', 'upplaga', 'uppl.'];\nfunction getPrintPreference(value) {\n return printPreference.findIndex(pp => pp === value);\n}\n\nfunction mergePrintData(value1, value2) {\n const [index1, print1, year1] = value1.split(' ');\n const [index2, print2, year2] = value2.split(' ');\n\n const betterIndex = index1 ? index1 : index2; // just to cheat eslint...\n\n // merge print1 and print2\n const betterPrint = getBetterPrint(print1, print2);\n if (!betterPrint) {\n return null;\n }\n\n const betterYear = getBetterYear(year1, year2);\n if (!betterYear) {\n return null;\n }\n\n return `${betterIndex} ${betterPrint} ${betterYear}`;\n\n function getBetterYear(y1, y2) {\n if (y1 === y2 || y2 === `[${y1}]`) {\n return y1;\n }\n if (y1 === `[${y2}]`) {\n return y2;\n }\n return null;\n }\n\n function getBetterPrint(print1, print2) {\n if (print1 === print2) {\n return print1;\n }\n\n const i1 = getPrintPreference(print1);\n const i2 = getPrintPreference(print2);\n if (i1 === -1 || i2 === -1) {\n return null;\n }\n if (i1 <= i2) {\n return printPreference[i1];\n }\n return printPreference[i2];\n }\n\n}\n\n\nfunction extractAllPrintData(relevantFields) {\n /* eslint-disable */\n // Gather data about 500 $a Lis\u00E4painokset.*\n let allPrintData = [];\n let i;\n let j;\n for (i=0; i < relevantFields.length; i++) {\n const value = fieldToPrintsString(relevantFields[i]);\n const fieldsPrintData = value.split('. - ');\n for (j=0; j < fieldsPrintData.length; j++) {\n let currPrintData = fieldsPrintData[j];\n // Example value: \"2. p. 2020\"\n const [ printIndex ] = currPrintData.split('.');\n if (allPrintData[printIndex] !== undefined) {\n if (allPrintData[printIndex] !== currPrintData ) {\n const mergedPrintData = mergePrintData(allPrintData[printIndex], currPrintData);\n if (!mergedPrintData) {\n return []; // reason for for-loops: exit function from within nested loops\n }\n currPrintData = mergedPrintData;\n }\n }\n allPrintData[printIndex] = currPrintData;\n }\n };\n return allPrintData.filter(p => p !== undefined);\n}\n\n\nexport function mergeLisapainokset(record) {\n const relevantFields = getRelevantFields(record);\n if (relevantFields.length < 2) {\n return;\n }\n\n const collapsedArray = extractAllPrintData(relevantFields);\n if (collapsedArray.length === 0) {\n return;\n }\n\n const content = \"Lis\u00E4painokset: \" + collapsedArray.join('. - ') + \".\";\n\n relevantFields[0].subfields[0].value = content; // Keep the place\n\n relevantFields.forEach((field, index) => {\n if (index > 0) {\n record.removeField(field);\n return;\n }\n });\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export default function () {\n\n return {\n description: 'Merge 500 $a Lis\u00E4painokset fields',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n mergeLisapainokset(record);\n return res;\n }\n\n function validate(record) {\n const relevantFields = getRelevantFields(record);\n if (relevantFields.length < 2) {\n return {message: [], 'valid': true}; // No action required\n }\n\n const printData = extractAllPrintData(relevantFields);\n if (printData.length === 0) {\n return {message: ['There are issues, but the fixer can not fix them!'], 'valid': false}; // No action required\n }\n\n return {message: [`Fixer can merge ${relevantFields.length} 500 $a Lis\u00E4painokset fields into one`], 'valid': false};\n }\n}\n\n\nfunction getRelevantFields(record) {\n return record.fields.filter(field => validLisapainosField(field));\n}\n\nfunction validLisapainosField(field) {\n // We are only interested in field 500 with a lone $a subfield.\n // Especially $9 FENNI<KEEP> should not be merged!\n if (field.tag !== '500' || field.subfields.length !== 1 || field.subfields[0].code !== 'a') {\n return false;\n }\n return field.subfields[0].value.match(/^(?:Lis\u00E4painokset|Lis\u00E4painos): (?:[1-9][0-9]*\\. (?:p\\.|painos|uppl\\.) [0-9]+\\.)(?: - [1-9][0-9]*\\. (?:p\\.|painos|uppl\\.) \\[?[0-9]+\\]?\\.)*$/u);\n}\n\nfunction fieldToPrintsString(field) {\n // Could this just be something on the lines of s/^\\S+ // ?\n return field.subfields[0].value.replace(/^(?:Lis\u00E4painokset|Lis\u00E4painos): /u, '').replace(/\\.$/u, '');\n}\n\nconst printPreference = ['painos', 'p.', 'upplaga', 'uppl.'];\nfunction getPrintPreference(value) {\n return printPreference.findIndex(pp => pp === value);\n}\n\nfunction mergePrintData(value1, value2) {\n const [index1, print1, year1] = value1.split(' ');\n const [index2, print2, year2] = value2.split(' ');\n\n const betterIndex = index1 ? index1 : index2; // just to cheat eslint...\n\n // merge print1 and print2\n const betterPrint = getBetterPrint(print1, print2);\n if (!betterPrint) {\n return null;\n }\n\n const betterYear = getBetterYear(year1, year2);\n if (!betterYear) {\n return null;\n }\n\n return `${betterIndex} ${betterPrint} ${betterYear}`;\n\n function getBetterYear(y1, y2) {\n if (y1 === y2 || y2 === `[${y1}]`) {\n return y1;\n }\n if (y1 === `[${y2}]`) {\n return y2;\n }\n return null;\n }\n\n function getBetterPrint(print1, print2) {\n if (print1 === print2) {\n return print1;\n }\n\n const i1 = getPrintPreference(print1);\n const i2 = getPrintPreference(print2);\n if (i1 === -1 || i2 === -1) {\n return null;\n }\n if (i1 <= i2) {\n return printPreference[i1];\n }\n return printPreference[i2];\n }\n\n}\n\n\nfunction extractAllPrintData(relevantFields) {\n /* eslint-disable */\n // Gather data about 500 $a Lis\u00E4painokset.*\n let allPrintData = [];\n let i;\n let j;\n for (i=0; i < relevantFields.length; i++) {\n const value = fieldToPrintsString(relevantFields[i]);\n const fieldsPrintData = value.split('. - ');\n for (j=0; j < fieldsPrintData.length; j++) {\n let currPrintData = fieldsPrintData[j];\n // Example value: \"2. p. 2020\"\n const [ printIndex ] = currPrintData.split('.');\n if (allPrintData[printIndex] !== undefined) {\n if (allPrintData[printIndex] !== currPrintData ) {\n const mergedPrintData = mergePrintData(allPrintData[printIndex], currPrintData);\n if (!mergedPrintData) {\n return []; // reason for for-loops: exit function from within nested loops\n }\n currPrintData = mergedPrintData;\n }\n }\n allPrintData[printIndex] = currPrintData;\n }\n };\n return allPrintData.filter(p => p !== undefined);\n}\n\n\nfunction mergeLisapainokset(record) {\n const relevantFields = getRelevantFields(record);\n if (relevantFields.length < 2) {\n return;\n }\n\n const collapsedArray = extractAllPrintData(relevantFields);\n if (collapsedArray.length === 0) {\n return;\n }\n\n const content = \"Lis\u00E4painokset: \" + collapsedArray.join('. - ') + \".\";\n\n relevantFields[0].subfields[0].value = content; // Keep the place\n\n relevantFields.forEach((field, index) => {\n if (index > 0) {\n record.removeField(field);\n return;\n }\n });\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["print1", "print2"]
7
7
  }
@@ -26,7 +26,7 @@ export default function() {
26
26
  return res;
27
27
  }
28
28
  }
29
- export function recordFixSubfield6OccurrenceNumbers(record) {
29
+ function recordFixSubfield6OccurrenceNumbers(record) {
30
30
  const fieldsContainingSubfield6 = record.fields.filter((field) => fieldHasSubfield(field, "6"));
31
31
  const orphanedFields = getOrphanedFields(fieldsContainingSubfield6);
32
32
  orphanedFields.forEach((field) => fieldFixOrphanedSubfields(field));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/resolveOrphanedSubfield6s.js"],
4
- "sourcesContent": ["import createDebugLogger from 'debug';\nimport {fieldHasSubfield, fieldToString, nvdebug, subfieldToString} from './utils.js';\nimport {fieldHasWantedTagAndOccurrenceNumber, isValidSubfield6, subfield6GetOccurrenceNumber, subfield6ResetOccurrenceNumber} from './subfield6Utils.js';\n\n// Relocated from melinda-marc-record-merge-reducers (and renamed)\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:resolveOrphanedSubfield6s');\n\nexport default function () {\n return {\n description: 'Remove occurrence-number-orphaned $6 subfields. In field 880, occurrence number becomes 00',\n validate, fix\n };\n\n function fix(record) {\n nvdebug('Fix SF6 orphaned occurrence numbers');\n const res = {message: [], fix: [], valid: true};\n //message.fix = [];\n\n // This can not really fail...\n recordFixSubfield6OccurrenceNumbers(record);\n\n //message.valid = !(message.message.length >= 1);\n return res;\n }\n\n function validate(record) {\n // Check max, and check number of different indexes\n nvdebug('Validate SF6 orphaned occurrence numbers', debug);\n const fieldsContainingSubfield6 = record.fields.filter(field => fieldHasSubfield(field, '6'));\n\n const orphanedFields = getOrphanedFields(fieldsContainingSubfield6);\n\n const res = {message: []};\n\n if (orphanedFields.length > 0) {\n res.message = [`${orphanedFields.length} orphaned occurrence number field(s) detected`];\n }\n res.valid = res.message.length < 1;\n return res;\n }\n}\n\nexport function recordFixSubfield6OccurrenceNumbers(record) {\n const fieldsContainingSubfield6 = record.fields.filter(field => fieldHasSubfield(field, '6'));\n const orphanedFields = getOrphanedFields(fieldsContainingSubfield6);\n\n orphanedFields.forEach(field => fieldFixOrphanedSubfields(field));\n\n function fieldFixOrphanedSubfields(field) {\n // Field 880: orphaned $6 subfields: occurrence number is changed to '00':\n if (field.tag === '880') {\n field.subfields.forEach(sf => field880FixOrphanedSubfield(sf));\n return;\n }\n // Non-880 fields get their orphaned $6s removed:\n const remainingSubfields = field.subfields.filter(sf => !isOrphanedSubfield(sf, field.tag, fieldsContainingSubfield6));\n if (remainingSubfields.length === 0) {\n record.removeField(field);\n return;\n }\n field.subfields = remainingSubfields;\n }\n\n function field880FixOrphanedSubfield(subfield) {\n if (!isOrphanedSubfield(subfield, '880', fieldsContainingSubfield6)) {\n return;\n }\n // convert occurrence number to 00\n subfield6ResetOccurrenceNumber(subfield, '00');\n }\n}\n\n\nfunction findPairForSubfield6OccurrenceNumber(subfield6, myTag, candPairFields) {\n // We keep the crap!\n if (!isValidSubfield6(subfield6)) {\n return undefined;\n }\n nvdebug(`LOOKING FOR PAIR: ${myTag} ${subfieldToString(subfield6)}`);\n candPairFields.forEach(field => fieldToString(field));\n\n // Only valid $6 value that fails to map to another field is iffy...\n const referredTag = subfield6.value.substring(0, 3);\n\n const occurrenceNumber = subfield6GetOccurrenceNumber(subfield6);\n if (occurrenceNumber === '00') {\n return undefined;\n }\n const tagAndOccurrenceNumber = `${myTag}-${occurrenceNumber}`;\n nvdebug(`Try to find occurrence number ${tagAndOccurrenceNumber} in field ${referredTag}...`);\n //const relevantFields = fields.filter(field => field.tag === referredTag && field.subfields.some(sf => subfield6GetOccurrenceNumber(sf) === occurrenceNumber));\n const relevantFields = candPairFields.filter(field => field.tag === referredTag && fieldHasWantedTagAndOccurrenceNumber(field, tagAndOccurrenceNumber));\n if (relevantFields.length === 0) {\n return undefined;\n }\n // This should always return just one (not sanity checking this for now):\n return relevantFields[0];\n}\n\nfunction isOrphanedSubfield(subfield, tag, pairCandidateFields) {\n if (!isValidSubfield6(subfield) || subfield6GetOccurrenceNumber(subfield) === '00') {\n return false;\n }\n return !findPairForSubfield6OccurrenceNumber(subfield, tag, pairCandidateFields);\n}\n\n\nfunction isOrphanedField(field, candidatePairFields) {\n return field.subfields.some(sf => isOrphanedSubfield(sf, field.tag, candidatePairFields));\n}\n\nfunction getOrphanedFields(relevantFields) {\n return relevantFields.filter(field => isOrphanedField(field, relevantFields));\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import createDebugLogger from 'debug';\nimport {fieldHasSubfield, fieldToString, nvdebug, subfieldToString} from './utils.js';\nimport {fieldHasWantedTagAndOccurrenceNumber, isValidSubfield6, subfield6GetOccurrenceNumber, subfield6ResetOccurrenceNumber} from './subfield6Utils.js';\n\n// Relocated from melinda-marc-record-merge-reducers (and renamed)\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:resolveOrphanedSubfield6s');\n\nexport default function () {\n return {\n description: 'Remove occurrence-number-orphaned $6 subfields. In field 880, occurrence number becomes 00',\n validate, fix\n };\n\n function fix(record) {\n nvdebug('Fix SF6 orphaned occurrence numbers');\n const res = {message: [], fix: [], valid: true};\n //message.fix = [];\n\n // This can not really fail...\n recordFixSubfield6OccurrenceNumbers(record);\n\n //message.valid = !(message.message.length >= 1);\n return res;\n }\n\n function validate(record) {\n // Check max, and check number of different indexes\n nvdebug('Validate SF6 orphaned occurrence numbers', debug);\n const fieldsContainingSubfield6 = record.fields.filter(field => fieldHasSubfield(field, '6'));\n\n const orphanedFields = getOrphanedFields(fieldsContainingSubfield6);\n\n const res = {message: []};\n\n if (orphanedFields.length > 0) {\n res.message = [`${orphanedFields.length} orphaned occurrence number field(s) detected`];\n }\n res.valid = res.message.length < 1;\n return res;\n }\n}\n\nfunction recordFixSubfield6OccurrenceNumbers(record) {\n const fieldsContainingSubfield6 = record.fields.filter(field => fieldHasSubfield(field, '6'));\n const orphanedFields = getOrphanedFields(fieldsContainingSubfield6);\n\n orphanedFields.forEach(field => fieldFixOrphanedSubfields(field));\n\n function fieldFixOrphanedSubfields(field) {\n // Field 880: orphaned $6 subfields: occurrence number is changed to '00':\n if (field.tag === '880') {\n field.subfields.forEach(sf => field880FixOrphanedSubfield(sf));\n return;\n }\n // Non-880 fields get their orphaned $6s removed:\n const remainingSubfields = field.subfields.filter(sf => !isOrphanedSubfield(sf, field.tag, fieldsContainingSubfield6));\n if (remainingSubfields.length === 0) {\n record.removeField(field);\n return;\n }\n field.subfields = remainingSubfields;\n }\n\n function field880FixOrphanedSubfield(subfield) {\n if (!isOrphanedSubfield(subfield, '880', fieldsContainingSubfield6)) {\n return;\n }\n // convert occurrence number to 00\n subfield6ResetOccurrenceNumber(subfield, '00');\n }\n}\n\n\nfunction findPairForSubfield6OccurrenceNumber(subfield6, myTag, candPairFields) {\n // We keep the crap!\n if (!isValidSubfield6(subfield6)) {\n return undefined;\n }\n nvdebug(`LOOKING FOR PAIR: ${myTag} ${subfieldToString(subfield6)}`);\n candPairFields.forEach(field => fieldToString(field));\n\n // Only valid $6 value that fails to map to another field is iffy...\n const referredTag = subfield6.value.substring(0, 3);\n\n const occurrenceNumber = subfield6GetOccurrenceNumber(subfield6);\n if (occurrenceNumber === '00') {\n return undefined;\n }\n const tagAndOccurrenceNumber = `${myTag}-${occurrenceNumber}`;\n nvdebug(`Try to find occurrence number ${tagAndOccurrenceNumber} in field ${referredTag}...`);\n //const relevantFields = fields.filter(field => field.tag === referredTag && field.subfields.some(sf => subfield6GetOccurrenceNumber(sf) === occurrenceNumber));\n const relevantFields = candPairFields.filter(field => field.tag === referredTag && fieldHasWantedTagAndOccurrenceNumber(field, tagAndOccurrenceNumber));\n if (relevantFields.length === 0) {\n return undefined;\n }\n // This should always return just one (not sanity checking this for now):\n return relevantFields[0];\n}\n\nfunction isOrphanedSubfield(subfield, tag, pairCandidateFields) {\n if (!isValidSubfield6(subfield) || subfield6GetOccurrenceNumber(subfield) === '00') {\n return false;\n }\n return !findPairForSubfield6OccurrenceNumber(subfield, tag, pairCandidateFields);\n}\n\n\nfunction isOrphanedField(field, candidatePairFields) {\n return field.subfields.some(sf => isOrphanedSubfield(sf, field.tag, candidatePairFields));\n}\n\nfunction getOrphanedFields(relevantFields) {\n return relevantFields.filter(field => isOrphanedField(field, relevantFields));\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import createDebugLogger from "debug";
2
2
  const debug = createDebugLogger("@natlibfi/melinda-marc-record-merge-reducers:utils");
3
3
  const debugDev = debug.extend("dev");
4
- import { melindaCustomMergeFields as melindaFields } from "./melindaCustomMergeFields.js";
4
+ import { melindaFieldSpecs } from "./melindaCustomMergeFields.js";
5
5
  export function isElectronicMaterial(record) {
6
6
  const f337s = record.get("337");
7
7
  return f337s.length > 0 && f337s.some((f) => fieldHasSubfield(f, "b", "c") && fieldHasSubfield(f, "2", "rdamedia"));
@@ -126,7 +126,7 @@ export function subfieldIsRepeatable(tag, subfieldCode) {
126
126
  if ("0159".indexOf(subfieldCode) > -1) {
127
127
  return true;
128
128
  }
129
- const fieldSpecs = melindaFields.fields.filter((field) => field.tag === tag);
129
+ const fieldSpecs = melindaFieldSpecs.fields.filter((field) => field.tag === tag);
130
130
  if (fieldSpecs.length !== 1) {
131
131
  nvdebug(` WARNING! Getting field ${tag} data failed! ${fieldSpecs.length} hits. Default value true is used for'${subfieldCode}' .`, debugDev);
132
132
  return true;
@@ -138,7 +138,7 @@ export function subfieldIsRepeatable(tag, subfieldCode) {
138
138
  return subfieldSpecs[0].repeatable;
139
139
  }
140
140
  function marc21GetTagsLegalIndicators(tag) {
141
- const fieldSpecs = melindaFields.fields.filter((field) => field.tag === tag);
141
+ const fieldSpecs = melindaFieldSpecs.fields.filter((field) => field.tag === tag);
142
142
  if (fieldSpecs.length === 0) {
143
143
  return void 0;
144
144
  }
package/dist/utils.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/utils.js"],
4
- "sourcesContent": ["import createDebugLogger from 'debug';\n\n//import fs from 'fs';\n//import path from 'path';\n\nconst debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:utils');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nimport {melindaCustomMergeFields as melindaFields} from './melindaCustomMergeFields.js';\n\n//JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'src', 'melindaCustomMergeFields.json'), 'utf8'));\n\nexport function isElectronicMaterial(record) {\n const f337s = record.get('337');\n\n return f337s.length > 0 && f337s.some(f => fieldHasSubfield(f, 'b', 'c') && fieldHasSubfield(f, '2', 'rdamedia'));\n}\n\nexport function nvdebug(message, func = undefined) {\n if (func) {\n func(message);\n }\n //console.info(message); // eslint-disable-line no-console\n}\n\nexport function fieldHasSubfield(field, subfieldCode, subfieldValue = null) {\n if (!field.subfields) {\n return false;\n }\n if (subfieldValue === null) {\n return field.subfields.some(sf => sf.code === subfieldCode);\n }\n return field.subfields.some(sf => sf.code === subfieldCode && subfieldValue === sf.value);\n}\n\nexport function subfieldToString(sf) {\n if (!sf.value) {\n return `\u2021${sf.code}`;\n }\n return `\u2021${sf.code} ${sf.value}`;\n}\n\nfunction normalizeIndicatorValue(val) {\n if (val === ' ') {\n return '#';\n }\n return val;\n}\n\nexport function recordToString(record) {\n const ldr = `LDR ${record.leader}`;\n const fields = record.fields.map(f => fieldToString(f));\n return `${ldr}\\n${fields.join('\\n')}`;\n}\n\nexport function removeSubfield(record, tag, subfieldCode) {\n record.fields = record.fields.map(field => {\n if (field.tag !== tag || !field.subfields) { // Don't procss irrelevant fields\n return field;\n }\n field.subfields = field.subfields.filter(sf => sf.code !== subfieldCode);\n if (field.subfields.length === 0) {\n return false;\n }\n return field;\n }).filter(field => field);\n}\n\nexport function recordRemoveValuelessSubfields(record) {\n record.fields = record.fields.map(field => {\n if (!field.subfields) { // Keep control fields\n return field;\n }\n // Remove empty subfields from datafields:\n field.subfields = field.subfields.filter(sf => sf.value);\n\n if (field.subfields && field.subfields.length === 0) {\n return false; // Return false instead of a field if field has no subfields left. These will soon be filtered out.\n }\n\n return field; //if field has subfields return it\n }).filter(field => field); // Filter those falses out\n}\n\nexport function fieldToString(f) {\n if ('subfields' in f) {\n return `${f.tag} ${normalizeIndicatorValue(f.ind1)}${normalizeIndicatorValue(f.ind2)}${formatSubfields(f)}`;\n }\n return `${f.tag} ${f.value}`;\n\n function formatSubfields(field) {\n return field.subfields.map(sf => ` ${subfieldToString(sf)}`).join('');\n }\n}\n\nexport function fieldsToString(fields) {\n return fields.map(f => fieldToString(f)).join('\\t__SEPARATOR__\\t');\n}\n\nexport function nvdebugFieldArray(fields, prefix = ' ', func = undefined) {\n fields.forEach(field => nvdebug(`${prefix}${fieldToString(field)}`, func));\n}\n\nexport function isControlSubfieldCode(subfieldCode) {\n if (['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'w'].includes(subfieldCode)) {\n return true;\n }\n return false;\n}\n\nexport function getCatalogingLanguage(record, defaultCatalogingLanguage = undefined) {\n const [field040] = record.get(/^040$/u);\n if (!field040) {\n return defaultCatalogingLanguage;\n }\n const [b] = field040.subfields.filter(sf => sf.code === 'b');\n if (!b) {\n return defaultCatalogingLanguage;\n }\n return b.value;\n}\n\n\nexport function uniqArray(arr) {\n return arr.filter((val, i) => arr.indexOf(val) === i);\n}\n\nexport function fieldsAreIdentical(field1, field2) {\n if (field1.tag !== field2.tag) { // NB! We are skipping normalizations here on purpose! They should be done beforehand...\n return false;\n }\n return fieldToString(field1) === fieldToString(field2);\n\n // The order of subfields is relevant! Bloody JS idiotisms make people use conditions such as:\n // return field1.subfields.every(sf => field2.subfields.some(sf2 => sf.code === sf2.code && sf.value === sf2.value));\n}\n\nexport function fieldHasNSubfields(field, subfieldCode/*, subfieldValue = null*/) {\n const relevantSubfields = field.subfields.filter(sf => sf.code === subfieldCode);\n //if (subfieldValue === null) {\n return relevantSubfields.length;\n //}\n //const subset = relevantSubfields.filter(value => value === subfieldValue);\n //return subset.length;\n}\n\nexport function removeCopyright(value) {\n return value.replace(/^(?:c|p|\u00A9|\u2117|Cop\\. ?) ?((?:1[0-9][0-9][0-9]|20[012][0-9])\\.?)$/ui, '$1');\n}\n\nfunction isNonStandardNonrepeatableSubfield(tag, subfieldCode) {\n // Put these into config or so...\n if (tag === '264') {\n return ['a', 'b', 'c'].includes(subfieldCode);\n }\n\n if (['336', '337', '338'].includes(tag)) {\n return ['a', 'b', '2'].includes(subfieldCode);\n }\n\n return false;\n}\n\n\nexport function subfieldIsRepeatable(tag, subfieldCode) {\n\n if (isNonStandardNonrepeatableSubfield(tag, subfieldCode)) {\n return false;\n }\n\n // These we know or \"know\":\n // NB! $5 is (according to MARC21 format) non-repeatable, and not usable in all fields, but Melinda has a local exception to this, see MET-300\n if ('0159'.indexOf(subfieldCode) > -1) {\n // Uh, can $0 appear on any field?\n return true;\n }\n\n const fieldSpecs = melindaFields.fields.filter(field => field.tag === tag);\n if (fieldSpecs.length !== 1) {\n nvdebug(` WARNING! Getting field ${tag} data failed! ${fieldSpecs.length} hits. Default value true is used for'${subfieldCode}' .`, debugDev);\n return true;\n }\n\n const subfieldSpecs = fieldSpecs[0].subfields.filter(subfield => subfield.code === subfieldCode);\n // Currently we don't support multiple $6 fields due to re-indexing limitations...\n // Well, $6 is non-repeatable, isn't it?!?\n // (This might actually already be fixed... Marginal issue, but check eventually.)\n if (subfieldSpecs.length !== 1 || subfieldCode === '6') {\n return false; // repeatable if not specified, I guess. Maybe add log or warn?\n }\n return subfieldSpecs[0].repeatable;\n}\n\nfunction marc21GetTagsLegalIndicators(tag) {\n const fieldSpecs = melindaFields.fields.filter(field => field.tag === tag);\n if (fieldSpecs.length === 0) {\n return undefined;\n }\n return fieldSpecs[0].indicators;\n}\n\nexport function marc21GetTagsLegalInd1Value(tag) {\n const indicator = marc21GetTagsLegalIndicators(tag);\n if (indicator === undefined) {\n return undefined;\n }\n return indicator.ind1;\n}\n\nexport function marc21GetTagsLegalInd2Value(tag) {\n const indicator = marc21GetTagsLegalIndicators(tag);\n if (indicator === undefined) {\n return undefined;\n }\n return indicator.ind2;\n}\n\nexport function nvdebugSubfieldArray(subfields, prefix = ' ', func = undefined) {\n subfields.forEach(subfield => nvdebug(`${prefix}${subfieldToString(subfield)}`, func));\n}\n\nexport function subfieldsAreIdentical(subfieldA, subfieldB) {\n return subfieldA.code === subfieldB.code && subfieldA.value === subfieldB.value;\n}\n\nexport function fieldHasMultipleSubfields(field, subfieldCode/*, subfieldValue = null*/) {\n return fieldHasNSubfields(field, subfieldCode) > 1;\n}\n\nexport function hasCopyright(value) {\n const modValue = removeCopyright(value);\n return value !== modValue;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import createDebugLogger from 'debug';\n\n//import fs from 'fs';\n//import path from 'path';\n\nconst debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:utils');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nimport {melindaFieldSpecs} from './melindaCustomMergeFields.js';\n\n//JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'src', 'melindaCustomMergeFields.json'), 'utf8'));\n\nexport function isElectronicMaterial(record) {\n const f337s = record.get('337');\n\n return f337s.length > 0 && f337s.some(f => fieldHasSubfield(f, 'b', 'c') && fieldHasSubfield(f, '2', 'rdamedia'));\n}\n\nexport function nvdebug(message, func = undefined) {\n if (func) {\n func(message);\n }\n //console.info(message); // eslint-disable-line no-console\n}\n\nexport function fieldHasSubfield(field, subfieldCode, subfieldValue = null) {\n if (!field.subfields) {\n return false;\n }\n if (subfieldValue === null) {\n return field.subfields.some(sf => sf.code === subfieldCode);\n }\n return field.subfields.some(sf => sf.code === subfieldCode && subfieldValue === sf.value);\n}\n\nexport function subfieldToString(sf) {\n if (!sf.value) {\n return `\u2021${sf.code}`;\n }\n return `\u2021${sf.code} ${sf.value}`;\n}\n\nfunction normalizeIndicatorValue(val) {\n if (val === ' ') {\n return '#';\n }\n return val;\n}\n\nexport function recordToString(record) {\n const ldr = `LDR ${record.leader}`;\n const fields = record.fields.map(f => fieldToString(f));\n return `${ldr}\\n${fields.join('\\n')}`;\n}\n\nexport function removeSubfield(record, tag, subfieldCode) {\n record.fields = record.fields.map(field => {\n if (field.tag !== tag || !field.subfields) { // Don't procss irrelevant fields\n return field;\n }\n field.subfields = field.subfields.filter(sf => sf.code !== subfieldCode);\n if (field.subfields.length === 0) {\n return false;\n }\n return field;\n }).filter(field => field);\n}\n\nexport function recordRemoveValuelessSubfields(record) {\n record.fields = record.fields.map(field => {\n if (!field.subfields) { // Keep control fields\n return field;\n }\n // Remove empty subfields from datafields:\n field.subfields = field.subfields.filter(sf => sf.value);\n\n if (field.subfields && field.subfields.length === 0) {\n return false; // Return false instead of a field if field has no subfields left. These will soon be filtered out.\n }\n\n return field; //if field has subfields return it\n }).filter(field => field); // Filter those falses out\n}\n\nexport function fieldToString(f) {\n if ('subfields' in f) {\n return `${f.tag} ${normalizeIndicatorValue(f.ind1)}${normalizeIndicatorValue(f.ind2)}${formatSubfields(f)}`;\n }\n return `${f.tag} ${f.value}`;\n\n function formatSubfields(field) {\n return field.subfields.map(sf => ` ${subfieldToString(sf)}`).join('');\n }\n}\n\nexport function fieldsToString(fields) {\n return fields.map(f => fieldToString(f)).join('\\t__SEPARATOR__\\t');\n}\n\nexport function nvdebugFieldArray(fields, prefix = ' ', func = undefined) {\n fields.forEach(field => nvdebug(`${prefix}${fieldToString(field)}`, func));\n}\n\nexport function isControlSubfieldCode(subfieldCode) {\n if (['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'w'].includes(subfieldCode)) {\n return true;\n }\n return false;\n}\n\nexport function getCatalogingLanguage(record, defaultCatalogingLanguage = undefined) {\n const [field040] = record.get(/^040$/u);\n if (!field040) {\n return defaultCatalogingLanguage;\n }\n const [b] = field040.subfields.filter(sf => sf.code === 'b');\n if (!b) {\n return defaultCatalogingLanguage;\n }\n return b.value;\n}\n\n\nexport function uniqArray(arr) {\n return arr.filter((val, i) => arr.indexOf(val) === i);\n}\n\nexport function fieldsAreIdentical(field1, field2) {\n if (field1.tag !== field2.tag) { // NB! We are skipping normalizations here on purpose! They should be done beforehand...\n return false;\n }\n return fieldToString(field1) === fieldToString(field2);\n\n // The order of subfields is relevant! Bloody JS idiotisms make people use conditions such as:\n // return field1.subfields.every(sf => field2.subfields.some(sf2 => sf.code === sf2.code && sf.value === sf2.value));\n}\n\nexport function fieldHasNSubfields(field, subfieldCode/*, subfieldValue = null*/) {\n const relevantSubfields = field.subfields.filter(sf => sf.code === subfieldCode);\n //if (subfieldValue === null) {\n return relevantSubfields.length;\n //}\n //const subset = relevantSubfields.filter(value => value === subfieldValue);\n //return subset.length;\n}\n\nexport function removeCopyright(value) {\n return value.replace(/^(?:c|p|\u00A9|\u2117|Cop\\. ?) ?((?:1[0-9][0-9][0-9]|20[012][0-9])\\.?)$/ui, '$1');\n}\n\nfunction isNonStandardNonrepeatableSubfield(tag, subfieldCode) {\n // Put these into config or so...\n if (tag === '264') {\n return ['a', 'b', 'c'].includes(subfieldCode);\n }\n\n if (['336', '337', '338'].includes(tag)) {\n return ['a', 'b', '2'].includes(subfieldCode);\n }\n\n return false;\n}\n\n\nexport function subfieldIsRepeatable(tag, subfieldCode) {\n\n if (isNonStandardNonrepeatableSubfield(tag, subfieldCode)) {\n return false;\n }\n\n // These we know or \"know\":\n // NB! $5 is (according to MARC21 format) non-repeatable, and not usable in all fields, but Melinda has a local exception to this, see MET-300\n if ('0159'.indexOf(subfieldCode) > -1) {\n // Uh, can $0 appear on any field?\n return true;\n }\n\n const fieldSpecs = melindaFieldSpecs.fields.filter(field => field.tag === tag);\n if (fieldSpecs.length !== 1) {\n nvdebug(` WARNING! Getting field ${tag} data failed! ${fieldSpecs.length} hits. Default value true is used for'${subfieldCode}' .`, debugDev);\n return true;\n }\n\n const subfieldSpecs = fieldSpecs[0].subfields.filter(subfield => subfield.code === subfieldCode);\n // Currently we don't support multiple $6 fields due to re-indexing limitations...\n // Well, $6 is non-repeatable, isn't it?!?\n // (This might actually already be fixed... Marginal issue, but check eventually.)\n if (subfieldSpecs.length !== 1 || subfieldCode === '6') {\n return false; // repeatable if not specified, I guess. Maybe add log or warn?\n }\n return subfieldSpecs[0].repeatable;\n}\n\nfunction marc21GetTagsLegalIndicators(tag) {\n const fieldSpecs = melindaFieldSpecs.fields.filter(field => field.tag === tag);\n if (fieldSpecs.length === 0) {\n return undefined;\n }\n return fieldSpecs[0].indicators;\n}\n\nexport function marc21GetTagsLegalInd1Value(tag) {\n const indicator = marc21GetTagsLegalIndicators(tag);\n if (indicator === undefined) {\n return undefined;\n }\n return indicator.ind1;\n}\n\nexport function marc21GetTagsLegalInd2Value(tag) {\n const indicator = marc21GetTagsLegalIndicators(tag);\n if (indicator === undefined) {\n return undefined;\n }\n return indicator.ind2;\n}\n\nexport function nvdebugSubfieldArray(subfields, prefix = ' ', func = undefined) {\n subfields.forEach(subfield => nvdebug(`${prefix}${subfieldToString(subfield)}`, func));\n}\n\nexport function subfieldsAreIdentical(subfieldA, subfieldB) {\n return subfieldA.code === subfieldB.code && subfieldA.value === subfieldB.value;\n}\n\nexport function fieldHasMultipleSubfields(field, subfieldCode/*, subfieldValue = null*/) {\n return fieldHasNSubfields(field, subfieldCode) > 1;\n}\n\nexport function hasCopyright(value) {\n const modValue = removeCopyright(value);\n return value !== modValue;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -15,7 +15,7 @@
15
15
  "url": "git@github.com:natlibfi/marc-record-validators-melinda.git"
16
16
  },
17
17
  "license": "MIT",
18
- "version": "12.0.0-alpha.2",
18
+ "version": "12.0.0-alpha.4",
19
19
  "main": "./dist/index.js",
20
20
  "publishConfig": {
21
21
  "access": "public"
@@ -33,20 +33,18 @@
33
33
  "dev:test": "cross-env DEBUG=@natlibfi/* NODE_ENV=test node --watch --test --experimental-test-coverage --test-reporter=spec './src/*.test.js' './src/**/*.test.js'",
34
34
  "dev:debug": "cross-env LOG_LEVEL=debug DEBUG=@natlibfi/* NODE_ENV=test"
35
35
  },
36
- "comment-sfs4900": "Package sfs-4900 npm version is 1.1.0, github 1.1.3.",
37
36
  "dependencies": {
38
37
  "@natlibfi/issn-verify": "^1.0.6",
39
38
  "@natlibfi/marc-record": "^10.0.0-alpha.1",
40
39
  "@natlibfi/marc-record-serializers": "^11.0.0-alpha.2",
41
- "@natlibfi/marc-record-validate": "^8.0.14",
40
+ "@natlibfi/marc-record-validate": "^9.0.0-alpha.1",
42
41
  "@natlibfi/melinda-commons": "^14.0.0-alpha.3",
43
42
  "@natlibfi/sfs-4900": "^2.0.0-alpha.3",
44
43
  "@natlibfi/iso9-1995": "^1.0.0-alpha.2",
45
- "@natlibfi/sru-client": "^7.0.0-alpha.1",
44
+ "@natlibfi/sru-client": "^7.0.0-alpha.3",
46
45
  "cld3-asm": "^4.0.0",
47
46
  "clone": "^2.1.2",
48
- "debug": "^4.4.0",
49
- "esbuild": "^0.25.9",
47
+ "debug": "^4.4.3",
50
48
  "isbn3": "^1.2.13",
51
49
  "langs": "^2.0.0",
52
50
  "xml2js": "^0.6.2",
@@ -56,10 +54,11 @@
56
54
  "@natlibfi/marc-record-validate": "^9.0.0-alpha.1"
57
55
  },
58
56
  "devDependencies": {
59
- "@natlibfi/fixugen": "^3.0.0-alpha.5",
60
- "@natlibfi/fixura": "^4.0.0-alpha.12",
57
+ "@natlibfi/fixugen": "^3.0.0-alpha.6",
58
+ "@natlibfi/fixura": "^4.0.0-alpha.13",
61
59
  "cross-env": "^10.0.0",
62
- "eslint": "^9.35.0",
60
+ "esbuild": "^0.25.10",
61
+ "eslint": "^9.36.0",
63
62
  "fetch-mock": "^12.5.4"
64
63
  },
65
64
  "overrides": {
package/src/index.js CHANGED
@@ -58,6 +58,29 @@ import UnicodeDecomposition from './unicode-decomposition.js';
58
58
  import UpdateField540 from './update-field-540.js';
59
59
  import Urn from './urn.js';
60
60
 
61
+ import {getCounterpart} from './merge-fields/counterpartField.js';
62
+
63
+ import {postprocessRecords} from './merge-fields/mergeOrAddPostprocess.js';
64
+ import {mergeField} from './merge-fields/mergeField.js';
65
+ import {fieldGetOccurrenceNumberPairs, fieldGetUnambiguousOccurrenceNumber, fieldToNormalizedString, fieldsToNormalizedString, get6s,
66
+ isValidSubfield6, recordGetMaxSubfield6OccurrenceNumberAsInteger,
67
+ intToOccurrenceNumberString, resetSubfield6Tag, subfield6ResetOccurrenceNumber, subfield6GetOccurrenceNumber,
68
+ subfield6GetOccurrenceNumberAsInteger} from './subfield6Utils.js';
69
+
70
+ import {getSubfield8LinkingNumber, isValidSubfield8, recordGetAllSubfield8LinkingNumbers, recordGetFieldsWithSubfield8LinkingNumber} from './subfield8Utils.js';
71
+
72
+ import {recordFixRelatorTerms} from './fixRelatorTerms.js';
73
+ import {fieldTrimSubfieldValues} from './normalizeFieldForComparison.js';
74
+ import {baseHasEqualOrHigherEncodingLevel, deleteAllPrepublicationNotesFromField500InNonPubRecord, encodingLevelIsBetterThanPrepublication, getEncodingLevel, isEnnakkotietoField, isEnnakkotietoSubfield} from './prepublicationUtils.js';
75
+ import {melindaFieldSpecs} from '@natlibfi/marc-record-validators-melinda/dist/melindaCustomMergeFields.js';
76
+
77
+ import {cloneAndRemovePunctuation} from './normalizeFieldForComparison.js';
78
+ import {removeWorsePrepubField500s, removeWorsePrepubField594s} from './prepublicationUtils.js';
79
+ import {fieldFixPunctuation} from './punctuation2.js';
80
+ import {recordResetSubfield6OccurrenceNumbers} from './reindexSubfield6OccurenceNumbers.js';
81
+ import {sortAdjacentSubfields} from './sortSubfields.js';
82
+ import {fieldsToString} from './utils.js';
83
+
61
84
  export {
62
85
  AccessRights,
63
86
  AddMissingField041,
@@ -116,5 +139,55 @@ export {
116
139
  UpdateField540,
117
140
  Urn,
118
141
  SortFields, // Keep this penultimate
119
- MergeFields // Run this last *iff* you want to use this at all
142
+ MergeFields, // Run this last *iff* you want to use this at all
143
+
144
+ // Functions for processing record... These should probably go to some other project.
145
+ // Too specific for marc-record-js though...
146
+ // 1. generic low level stuff
147
+ getEncodingLevel,
148
+
149
+ // 2. text normalizations (eg. for similarity comparisons, field merge)
150
+ cloneAndRemovePunctuation,
151
+ fieldFixPunctuation,
152
+ fieldToNormalizedString,
153
+ fieldTrimSubfieldValues,
154
+ fieldsToNormalizedString,
155
+ fieldsToString,
156
+ recordFixRelatorTerms,
157
+ sortAdjacentSubfields,
158
+
159
+ // 3. prepublication stuff
160
+ baseHasEqualOrHigherEncodingLevel,
161
+ deleteAllPrepublicationNotesFromField500InNonPubRecord,
162
+ encodingLevelIsBetterThanPrepublication,
163
+ isEnnakkotietoField,
164
+ isEnnakkotietoSubfield,
165
+ removeWorsePrepubField500s,
166
+ removeWorsePrepubField594s,
167
+
168
+ // 4. subfield $6 related functions
169
+ fieldGetOccurrenceNumberPairs,
170
+ get6s,
171
+ fieldGetUnambiguousOccurrenceNumber,
172
+ intToOccurrenceNumberString,
173
+ isValidSubfield6,
174
+ recordGetMaxSubfield6OccurrenceNumberAsInteger,
175
+ recordResetSubfield6OccurrenceNumbers,
176
+ resetSubfield6Tag,
177
+ subfield6ResetOccurrenceNumber,
178
+ subfield6GetOccurrenceNumber,
179
+ subfield6GetOccurrenceNumberAsInteger,
180
+
181
+ // 5. subfield $8 related functions
182
+ getSubfield8LinkingNumber,
183
+ isValidSubfield8,
184
+ recordGetAllSubfield8LinkingNumbers,
185
+ recordGetFieldsWithSubfield8LinkingNumber,
186
+
187
+ // 6. merge, other
188
+ getCounterpart, // field merge: finds a similar field with which a field can merge
189
+ melindaFieldSpecs, // contains information about the legal fields and subfields, and their repeatability
190
+ mergeField,
191
+ postprocessRecords // clean-up function that cleans up both base and source record (which may be the same)
192
+
120
193
  };
@@ -229,7 +229,7 @@ function getLanguages(record) {
229
229
 
230
230
  }
231
231
 
232
- export function recordNormalizeIndicators(record) {
232
+ function recordNormalizeIndicators(record) {
233
233
  recordNormalize490(record);
234
234
 
235
235
  // Language is used to handle non-filing indicators
@@ -1,4 +1,4 @@
1
- export const melindaCustomMergeFields = {'fields':
1
+ export const melindaFieldSpecs = {'fields':
2
2
  [
3
3
  {
4
4
  'tag': 'leader',
@@ -127,7 +127,7 @@ function extractAllPrintData(relevantFields) {
127
127
  }
128
128
 
129
129
 
130
- export function mergeLisapainokset(record) {
130
+ function mergeLisapainokset(record) {
131
131
  const relevantFields = getRelevantFields(record);
132
132
  if (relevantFields.length < 2) {
133
133
  return;
@@ -41,7 +41,7 @@ export default function () {
41
41
  }
42
42
  }
43
43
 
44
- export function recordFixSubfield6OccurrenceNumbers(record) {
44
+ function recordFixSubfield6OccurrenceNumbers(record) {
45
45
  const fieldsContainingSubfield6 = record.fields.filter(field => fieldHasSubfield(field, '6'));
46
46
  const orphanedFields = getOrphanedFields(fieldsContainingSubfield6);
47
47
 
package/src/utils.js CHANGED
@@ -7,7 +7,7 @@ const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:ut
7
7
  //const debugData = debug.extend('data');
8
8
  const debugDev = debug.extend('dev');
9
9
 
10
- import {melindaCustomMergeFields as melindaFields} from './melindaCustomMergeFields.js';
10
+ import {melindaFieldSpecs} from './melindaCustomMergeFields.js';
11
11
 
12
12
  //JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'src', 'melindaCustomMergeFields.json'), 'utf8'));
13
13
 
@@ -176,7 +176,7 @@ export function subfieldIsRepeatable(tag, subfieldCode) {
176
176
  return true;
177
177
  }
178
178
 
179
- const fieldSpecs = melindaFields.fields.filter(field => field.tag === tag);
179
+ const fieldSpecs = melindaFieldSpecs.fields.filter(field => field.tag === tag);
180
180
  if (fieldSpecs.length !== 1) {
181
181
  nvdebug(` WARNING! Getting field ${tag} data failed! ${fieldSpecs.length} hits. Default value true is used for'${subfieldCode}' .`, debugDev);
182
182
  return true;
@@ -193,7 +193,7 @@ export function subfieldIsRepeatable(tag, subfieldCode) {
193
193
  }
194
194
 
195
195
  function marc21GetTagsLegalIndicators(tag) {
196
- const fieldSpecs = melindaFields.fields.filter(field => field.tag === tag);
196
+ const fieldSpecs = melindaFieldSpecs.fields.filter(field => field.tag === tag);
197
197
  if (fieldSpecs.length === 0) {
198
198
  return undefined;
199
199
  }