@natlibfi/marc-record-validators-melinda 12.0.0-alpha.6 → 12.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -121,6 +121,15 @@ function normalize245Indicator1(field, record) {
121
121
  const field1XX = record.get("^1..$");
122
122
  field.ind1 = field1XX.length === 0 ? "0" : "1";
123
123
  }
124
+ function noDisplayConstantGenerated520Indicator1(field) {
125
+ if (field.tag !== "520") {
126
+ return;
127
+ }
128
+ const as = field.subfields.filter((sf) => sf.code === "a");
129
+ if (as.length === 1 && ["Abstract.", "Abstrakt.", "Abstrakti.", "Abstract.", "English Summary.", "Sammandrag.", "Tiivistelm\xE4."].includes(field.subfields[0].value)) {
130
+ field.ind1 = "8";
131
+ }
132
+ }
124
133
  function normalize776Indicator2(field) {
125
134
  if (field.tag !== "776") {
126
135
  return;
@@ -173,6 +182,7 @@ function recordNormalizeIndicators(record) {
173
182
  function fieldNormalizeIndicators(field, record, languages) {
174
183
  normalize084Indicator1(field);
175
184
  normalize245Indicator1(field, record);
185
+ noDisplayConstantGenerated520Indicator1(field);
176
186
  normalizeNonFilingIndicator1(field, languages);
177
187
  normalizeNonFilingIndicator2(field, languages);
178
188
  normalize776Indicator2(field);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/indicator-fixes.js"],
4
- "sourcesContent": ["// Relocated from melinda-marc-record-merge-reducers (and renamed)\n//import createDebugLogger from 'debug';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');\n\nimport {fieldToString} from './utils.js';\n\n\nexport default function () {\n\n return {\n description: 'Normalizes indicator values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n recordNormalizeIndicators(record);\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n validateRecord(record, res);\n\n res.valid = res.message.length < 1;\n return res;\n }\n\n\n function validateRecord(record, res) {\n //nvdebug(record);\n const clonedFields = JSON.parse(JSON.stringify(record.fields));\n recordNormalizeIndicators(record);\n\n record.fields.forEach((field, index) => compareFields(field, index));\n\n function compareFields(field, index) {\n const origFieldAsString = fieldToString(clonedFields[index]);\n //const clonedFieldAsString = fieldToString(field);\n if (clonedFields[index].ind1 !== field.ind1) {\n //nvdebug(`FIX IND1: '${clonedFields[index].ind1}' => '${field.ind1}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND1 for '${origFieldAsString}' is '${field.ind1}'`);\n }\n if (clonedFields[index].ind2 !== field.ind2) {\n //nvdebug(`FIX IND2: '${clonedFields[index].ind2}' => '${field.ind2}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND2 for '${origFieldAsString}' is '${field.ind2}'`);\n }\n }\n // Validator should not change the original record:\n record.fields = clonedFields;\n return;\n }\n}\n\n\nconst ind1NonFilingChars = ['130', '630', '730', '740'];\nconst ind2NonFilingChars = ['222', '240', '242', '243', '245', '830'];\n\nfunction hasNonFilingIndicator1(field) {\n return ind1NonFilingChars.includes(field.tag);\n}\n\nfunction modifiableIndicatorValue(value) {\n // If field contains a legit-looking value, don't try to modify it here...\n return !['9', '8', '7', '6', '5', '4', '3', '2', '1'].includes(value);\n}\n\nfunction hasNonFilingIndicator2(field) {\n return ind2NonFilingChars.includes(field.tag);\n}\n\nfunction valueBeginsWithDeterminer(value, cands) {\n return cands.find(cand => value.substring(0, cand.length) === cand);\n}\n\nfunction determineNonFilingIndicatorValue(field, languages = undefined) {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (!subfieldA) {\n // nvdebug(' Subfield $a miss!');\n return;\n }\n\n const name = subfieldA.value.toLowerCase();\n\n if (languages.includes('eng')) {\n const match = valueBeginsWithDeterminer(name, ['a ', 'an ', 'the ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('fre')) {\n const match = valueBeginsWithDeterminer(name, ['l\\'', 'le ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('ger')) {\n const match = valueBeginsWithDeterminer(name, ['das ', 'der ', 'die ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('swe')) {\n const match = valueBeginsWithDeterminer(name, ['en ', 'ett ']);\n if (match) {\n return `${match.length}`;\n }\n if (name.match(/^de[nt] /u) && !name.match(/^de[nt] som /u)) {\n return '4';\n }\n }\n\n // Fallback-ish: try to guess even without languages:\n const match = valueBeginsWithDeterminer(name, ['the ']);\n if (match) {\n return `${match.length}`;\n }\n if (name.match(/^a /u) && !languages.includes('hun') && !name.match(/^a (?:b |la )/u)) { // Skip \"a b c\", \"a la carte\"...\n return '2';\n }\n\n return '0';\n}\n\nfunction normalizeNonFilingIndicator1(field, languages = []) {\n if (!hasNonFilingIndicator1(field) || !modifiableIndicatorValue(field.ind1)) {\n return;\n }\n\n field.ind1 = determineNonFilingIndicatorValue(field, languages);\n}\n\nfunction normalizeNonFilingIndicator2(field, languages = []) {\n if (!hasNonFilingIndicator2(field) || !modifiableIndicatorValue(field.ind2)) {\n return;\n }\n\n field.ind2 = determineNonFilingIndicatorValue(field, languages);\n}\n\nconst fiktiivisenAineistonLisaluokatFI = ['El\u00E4imet', 'Erotiikka', 'Er\u00E4', 'Fantasia', 'Historia', 'Huumori', 'J\u00E4nnitys', 'Kauhu', 'Novellit', 'Romantiikka', 'Scifi', 'Sota', 'Urheilu', 'Uskonto'];\n\nfunction containsFiktiivisenAineistonLisaluokka(field) {\n // Should we check Swedish versions as well?\n return field.subfields.some(sf => sf.code === 'a' && fiktiivisenAineistonLisaluokatFI.includes(sf.value));\n}\n\nfunction normalize084Indicator1(field) {\n if (field.tag !== '084') {\n return;\n }\n\n // https://marc21.kansalliskirjasto.fi/bib/05X-08X.htm#084 and https://finto.fi/ykl/fi/page/fiktioluokka\n if (field.ind1 !== '9' && containsFiktiivisenAineistonLisaluokka(field) && field.subfields.some(sf => sf.code === '2' && sf.value === 'ykl')) {\n field.ind1 = '9';\n return;\n }\n}\n\nfunction normalize245Indicator1(field, record) {\n if (field.tag !== '245') {\n return;\n }\n const field1XX = record.get('^1..$');\n field.ind1 = field1XX.length === 0 ? '0' : '1';\n}\n\nfunction normalize776Indicator2(field) {\n if (field.tag !== '776') {\n return;\n }\n // If subfield $i exists, ind2 must me '8'\n if (field.subfields.some(sf => sf.code === 'i')) {\n field.ind2 = '8';\n return;\n }\n}\n\n\nfunction recordNormalize490(record) {\n const fields490 = record.get('^490$');\n const fields8XX = record.get('^(?:800|810|811|830)$');\n\n if (fields490.length === 0) {\n return;\n }\n if (fields490.length <= fields8XX.length) {\n // Trace found for each field 490:\n fields490.forEach(f => {\n f.ind1 = '1';\n });\n return;\n }\n if (fields8XX.length === 0) { // Fields 490 are always untraced (no traces found)\n fields490.forEach(f => {\n f.ind1 = '0';\n });\n return;\n }\n // For other combinations we just can't be sure, so leave them as they are.\n}\n\n\nfunction getLanguages(record) {\n const langFields = record.get('^041$');\n\n if (langFields.length === 0) {\n return [];\n }\n\n return langFields[0].subfields.filter(sf => isRelevantSubfield(sf)).map(subfield => subfield.value);\n\n function isRelevantSubfield(subfield) {\n if (!['a', 'd', 'h'].includes(subfield.code)) {\n return false;\n }\n if (subfield.value.length !== 3) {\n return false;\n }\n // We could require /^[a-z][a-z][a-z]$/ etc as well, but it's not really that relevant.\n return true;\n }\n\n}\n\nfunction recordNormalizeIndicators(record) {\n recordNormalize490(record);\n\n // Language is used to handle non-filing indicators\n const languages = getLanguages(record);\n\n record.fields.forEach(field => fieldNormalizeIndicators(field, record, languages));\n\n}\n\nfunction fieldNormalizeIndicators(field, record, languages) {\n normalize084Indicator1(field);\n normalize245Indicator1(field, record);\n normalizeNonFilingIndicator1(field, languages);\n normalizeNonFilingIndicator2(field, languages);\n normalize776Indicator2(field);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["// Relocated from melinda-marc-record-merge-reducers (and renamed)\n//import createDebugLogger from 'debug';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:normalizeIdentifiers');\n\nimport {fieldToString} from './utils.js';\n\n\nexport default function () {\n\n return {\n description: 'Normalizes indicator values',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n recordNormalizeIndicators(record);\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n validateRecord(record, res);\n\n res.valid = res.message.length < 1;\n return res;\n }\n\n\n function validateRecord(record, res) {\n //nvdebug(record);\n const clonedFields = JSON.parse(JSON.stringify(record.fields));\n recordNormalizeIndicators(record);\n\n record.fields.forEach((field, index) => compareFields(field, index));\n\n function compareFields(field, index) {\n const origFieldAsString = fieldToString(clonedFields[index]);\n //const clonedFieldAsString = fieldToString(field);\n if (clonedFields[index].ind1 !== field.ind1) {\n //nvdebug(`FIX IND1: '${clonedFields[index].ind1}' => '${field.ind1}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND1 for '${origFieldAsString}' is '${field.ind1}'`);\n }\n if (clonedFields[index].ind2 !== field.ind2) {\n //nvdebug(`FIX IND2: '${clonedFields[index].ind2}' => '${field.ind2}': ${clonedFieldAsString}`);\n res.message.push(`Expected IND2 for '${origFieldAsString}' is '${field.ind2}'`);\n }\n }\n // Validator should not change the original record:\n record.fields = clonedFields;\n return;\n }\n}\n\n\nconst ind1NonFilingChars = ['130', '630', '730', '740'];\nconst ind2NonFilingChars = ['222', '240', '242', '243', '245', '830'];\n\nfunction hasNonFilingIndicator1(field) {\n return ind1NonFilingChars.includes(field.tag);\n}\n\nfunction modifiableIndicatorValue(value) {\n // If field contains a legit-looking value, don't try to modify it here...\n return !['9', '8', '7', '6', '5', '4', '3', '2', '1'].includes(value);\n}\n\nfunction hasNonFilingIndicator2(field) {\n return ind2NonFilingChars.includes(field.tag);\n}\n\nfunction valueBeginsWithDeterminer(value, cands) {\n return cands.find(cand => value.substring(0, cand.length) === cand);\n}\n\nfunction determineNonFilingIndicatorValue(field, languages = undefined) {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (!subfieldA) {\n // nvdebug(' Subfield $a miss!');\n return;\n }\n\n const name = subfieldA.value.toLowerCase();\n\n if (languages.includes('eng')) {\n const match = valueBeginsWithDeterminer(name, ['a ', 'an ', 'the ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('fre')) {\n const match = valueBeginsWithDeterminer(name, ['l\\'', 'le ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('ger')) {\n const match = valueBeginsWithDeterminer(name, ['das ', 'der ', 'die ']);\n if (match) {\n return `${match.length}`;\n }\n }\n\n if (languages.includes('swe')) {\n const match = valueBeginsWithDeterminer(name, ['en ', 'ett ']);\n if (match) {\n return `${match.length}`;\n }\n if (name.match(/^de[nt] /u) && !name.match(/^de[nt] som /u)) {\n return '4';\n }\n }\n\n // Fallback-ish: try to guess even without languages:\n const match = valueBeginsWithDeterminer(name, ['the ']);\n if (match) {\n return `${match.length}`;\n }\n if (name.match(/^a /u) && !languages.includes('hun') && !name.match(/^a (?:b |la )/u)) { // Skip \"a b c\", \"a la carte\"...\n return '2';\n }\n\n return '0';\n}\n\nfunction normalizeNonFilingIndicator1(field, languages = []) {\n if (!hasNonFilingIndicator1(field) || !modifiableIndicatorValue(field.ind1)) {\n return;\n }\n\n field.ind1 = determineNonFilingIndicatorValue(field, languages);\n}\n\nfunction normalizeNonFilingIndicator2(field, languages = []) {\n if (!hasNonFilingIndicator2(field) || !modifiableIndicatorValue(field.ind2)) {\n return;\n }\n\n field.ind2 = determineNonFilingIndicatorValue(field, languages);\n}\n\nconst fiktiivisenAineistonLisaluokatFI = ['El\u00E4imet', 'Erotiikka', 'Er\u00E4', 'Fantasia', 'Historia', 'Huumori', 'J\u00E4nnitys', 'Kauhu', 'Novellit', 'Romantiikka', 'Scifi', 'Sota', 'Urheilu', 'Uskonto'];\n\nfunction containsFiktiivisenAineistonLisaluokka(field) {\n // Should we check Swedish versions as well?\n return field.subfields.some(sf => sf.code === 'a' && fiktiivisenAineistonLisaluokatFI.includes(sf.value));\n}\n\nfunction normalize084Indicator1(field) {\n if (field.tag !== '084') {\n return;\n }\n\n // https://marc21.kansalliskirjasto.fi/bib/05X-08X.htm#084 and https://finto.fi/ykl/fi/page/fiktioluokka\n if (field.ind1 !== '9' && containsFiktiivisenAineistonLisaluokka(field) && field.subfields.some(sf => sf.code === '2' && sf.value === 'ykl')) {\n field.ind1 = '9';\n return;\n }\n}\n\nfunction normalize245Indicator1(field, record) {\n if (field.tag !== '245') {\n return;\n }\n const field1XX = record.get('^1..$');\n field.ind1 = field1XX.length === 0 ? '0' : '1';\n}\n\nfunction noDisplayConstantGenerated520Indicator1(field) {\n if (field.tag !== '520') {\n return;\n }\n const as = field.subfields.filter(sf => sf.code === 'a');\n // Set ind1=8 \"no display constant generated\" fro certain values (part of MELKEHITYS-2579):\n if (as.length === 1 && ['Abstract.', 'Abstrakt.', 'Abstrakti.', 'Abstract.', 'English Summary.', 'Sammandrag.', 'Tiivistelm\u00E4.'].includes(field.subfields[0].value)) {\n field.ind1 = '8';\n }\n\n}\n\nfunction normalize776Indicator2(field) {\n if (field.tag !== '776') {\n return;\n }\n // If subfield $i exists, ind2 must me '8'\n if (field.subfields.some(sf => sf.code === 'i')) {\n field.ind2 = '8';\n return;\n }\n}\n\n\nfunction recordNormalize490(record) {\n const fields490 = record.get('^490$');\n const fields8XX = record.get('^(?:800|810|811|830)$');\n\n if (fields490.length === 0) {\n return;\n }\n if (fields490.length <= fields8XX.length) {\n // Trace found for each field 490:\n fields490.forEach(f => {\n f.ind1 = '1';\n });\n return;\n }\n if (fields8XX.length === 0) { // Fields 490 are always untraced (no traces found)\n fields490.forEach(f => {\n f.ind1 = '0';\n });\n return;\n }\n // For other combinations we just can't be sure, so leave them as they are.\n}\n\n\nfunction getLanguages(record) {\n const langFields = record.get('^041$');\n\n if (langFields.length === 0) {\n return [];\n }\n\n return langFields[0].subfields.filter(sf => isRelevantSubfield(sf)).map(subfield => subfield.value);\n\n function isRelevantSubfield(subfield) {\n if (!['a', 'd', 'h'].includes(subfield.code)) {\n return false;\n }\n if (subfield.value.length !== 3) {\n return false;\n }\n // We could require /^[a-z][a-z][a-z]$/ etc as well, but it's not really that relevant.\n return true;\n }\n\n}\n\nfunction recordNormalizeIndicators(record) {\n recordNormalize490(record);\n\n // Language is used to handle non-filing indicators\n const languages = getLanguages(record);\n\n record.fields.forEach(field => fieldNormalizeIndicators(field, record, languages));\n\n}\n\nfunction fieldNormalizeIndicators(field, record, languages) {\n normalize084Indicator1(field);\n normalize245Indicator1(field, record);\n noDisplayConstantGenerated520Indicator1(field);\n normalizeNonFilingIndicator1(field, languages);\n normalizeNonFilingIndicator2(field, languages);\n normalize776Indicator2(field);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["match"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import { subfieldArraysContainSameData } from "../utils.js";
2
- function tagToDataProvenanceSubfieldCode(tag) {
2
+ export function tagToDataProvenanceSubfieldCode(tag) {
3
3
  if (["533", "800", "810", "811", "830"].includes(tag)) {
4
4
  return "y";
5
5
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/merge-fields/dataProvenance.js"],
4
- "sourcesContent": ["// See https://www.loc.gov/marc/bibliographic/bdapndxj.html for details\n\nimport {subfieldArraysContainSameData} from \"../utils.js\";\n\nfunction tagToDataProvenanceSubfieldCode(tag) {\n if ( ['533', '800', '810', '811', '830'].includes(tag)) {\n return 'y';\n }\n if ( tag === '856' || tag === '857' ) {\n return 'e';\n }\n\n if ( tag.match(/^7[678]/u) ) {\n return 'l'\n }\n\n if ( tag.match(/^00/u)) {\n return undefined;\n }\n return '7';\n}\n\n\nexport function provenanceSubfieldsPermitMerge(baseField, sourceField) {\n const provinanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);\n if (!baseField.subfields) {\n return true;\n }\n if (provinanceSubfieldCode === undefined) {\n return false;\n }\n\n const baseProvinanceSubfields = baseField.subfields.filter(sf => sf.code === provinanceSubfieldCode);\n const sourceProvinanceSubfields = sourceField.subfields.filter(sf => sf.code === provinanceSubfieldCode);\n\n // Currently we just compare two arrays. Later on we might do something more sophisticated with specific $7 data provenance category/relationship codes,\n // or actual values.\n\n return subfieldArraysContainSameData(baseProvinanceSubfields, sourceProvinanceSubfields);\n\n}"],
5
- "mappings": "AAEA,SAAQ,qCAAoC;AAE5C,SAAS,gCAAgC,KAAK;AAC1C,MAAK,CAAC,OAAO,OAAO,OAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACpD,WAAO;AAAA,EACX;AACA,MAAK,QAAQ,SAAS,QAAQ,OAAQ;AAClC,WAAO;AAAA,EACX;AAEA,MAAK,IAAI,MAAM,UAAU,GAAI;AACzB,WAAO;AAAA,EACX;AAEA,MAAK,IAAI,MAAM,MAAM,GAAG;AACpB,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAGO,gBAAS,+BAA+B,WAAW,aAAa;AACnE,QAAM,yBAAyB,gCAAgC,UAAU,GAAG;AAC5E,MAAI,CAAC,UAAU,WAAW;AACtB,WAAO;AAAA,EACX;AACA,MAAI,2BAA2B,QAAW;AACtC,WAAO;AAAA,EACX;AAEA,QAAM,0BAA0B,UAAU,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AACnG,QAAM,4BAA4B,YAAY,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AAKvG,SAAO,8BAA8B,yBAAyB,yBAAyB;AAE3F;",
4
+ "sourcesContent": ["// See https://www.loc.gov/marc/bibliographic/bdapndxj.html for details\n\nimport {subfieldArraysContainSameData} from \"../utils.js\";\n\nexport function tagToDataProvenanceSubfieldCode(tag) {\n if ( ['533', '800', '810', '811', '830'].includes(tag)) {\n return 'y';\n }\n if ( tag === '856' || tag === '857' ) {\n return 'e';\n }\n\n if ( tag.match(/^7[678]/u) ) {\n return 'l'\n }\n\n if ( tag.match(/^00/u)) {\n return undefined;\n }\n return '7';\n}\n\n\nexport function provenanceSubfieldsPermitMerge(baseField, sourceField) {\n const provinanceSubfieldCode = tagToDataProvenanceSubfieldCode(baseField.tag);\n if (!baseField.subfields) {\n return true;\n }\n if (provinanceSubfieldCode === undefined) {\n return false;\n }\n\n const baseProvinanceSubfields = baseField.subfields.filter(sf => sf.code === provinanceSubfieldCode);\n const sourceProvinanceSubfields = sourceField.subfields.filter(sf => sf.code === provinanceSubfieldCode);\n\n // Currently we just compare two arrays. Later on we might do something more sophisticated with specific $7 data provenance category/relationship codes,\n // or actual values.\n\n return subfieldArraysContainSameData(baseProvinanceSubfields, sourceProvinanceSubfields);\n\n}"],
5
+ "mappings": "AAEA,SAAQ,qCAAoC;AAErC,gBAAS,gCAAgC,KAAK;AACjD,MAAK,CAAC,OAAO,OAAO,OAAO,OAAO,KAAK,EAAE,SAAS,GAAG,GAAG;AACpD,WAAO;AAAA,EACX;AACA,MAAK,QAAQ,SAAS,QAAQ,OAAQ;AAClC,WAAO;AAAA,EACX;AAEA,MAAK,IAAI,MAAM,UAAU,GAAI;AACzB,WAAO;AAAA,EACX;AAEA,MAAK,IAAI,MAAM,MAAM,GAAG;AACpB,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAGO,gBAAS,+BAA+B,WAAW,aAAa;AACnE,QAAM,yBAAyB,gCAAgC,UAAU,GAAG;AAC5E,MAAI,CAAC,UAAU,WAAW;AACtB,WAAO;AAAA,EACX;AACA,MAAI,2BAA2B,QAAW;AACtC,WAAO;AAAA,EACX;AAEA,QAAM,0BAA0B,UAAU,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AACnG,QAAM,4BAA4B,YAAY,UAAU,OAAO,QAAM,GAAG,SAAS,sBAAsB;AAKvG,SAAO,8BAA8B,yBAAyB,yBAAyB;AAE3F;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,7 @@
1
1
  import { validateSingleField } from "./ending-punctuation.js";
2
+ import { tagToDataProvenanceSubfieldCode } from "./merge-fields/dataProvenance.js";
2
3
  import { fieldGetUnambiguousTag } from "./subfield6Utils.js";
3
- import { fieldToString, nvdebug } from "./utils.js";
4
+ import { fieldToString, isControlSubfieldCode, nvdebug } from "./utils.js";
4
5
  import clone from "clone";
5
6
  const descriptionString = "Remove invalid and add valid punctuation to data fields";
6
7
  export default function() {
@@ -26,11 +27,15 @@ export default function() {
26
27
  return res;
27
28
  }
28
29
  }
29
- function isControlSubfield(subfield) {
30
- return ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(subfield.code);
30
+ function isIrrelevantSubfield(subfield, tag) {
31
+ const dataProvenanceSubfieldCode = tagToDataProvenanceSubfieldCode(tag);
32
+ if (subfield.code === dataProvenanceSubfieldCode) {
33
+ return true;
34
+ }
35
+ return isControlSubfieldCode(subfield.code);
31
36
  }
32
37
  function getNextRelevantSubfield(field, currSubfieldIndex) {
33
- return field.subfields.find((subfield, index) => index > currSubfieldIndex && !isControlSubfield(subfield));
38
+ return field.subfields.find((subfield, index) => index > currSubfieldIndex && !isIrrelevantSubfield(subfield, field.tag));
34
39
  }
35
40
  export function fieldGetFixedString(field, add = true) {
36
41
  const cloneField = clone(field);
@@ -95,7 +100,8 @@ const linkingEntryRemoveWhatever = [
95
100
  { "code": "i", "followedBy": "at", "remove": / ?:$/u },
96
101
  // ':'
97
102
  { "code": "at", "remove": /\.$/u },
98
- { "code": "abdghiklmnopqrstuwxyz", "followedBy": "abdghiklmnopqrstuwxyz", "remove": /\. -$/u }
103
+ // Only ". -" separator is still used in music. We can strip it, but can only create the non-music punctuation!
104
+ { "code": "abdghiklmnopqrstuwxyz", "followedBy": "abdghiklmnopqrstuwxyz#", "remove": /\. -$/u }
99
105
  ];
100
106
  const crappy24X = [
101
107
  { "code": "abnp", "followedBy": "!c", "remove": / \/$/u },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/punctuation2.js"],
4
- "sourcesContent": ["/*\n* punctuation.js -- try and fix a marc field punctuation\n*\n* Author(s): Nicholas Volk <nicholas.volk@helsinki.fi>\n*\n* NOTE #1: https://www.kiwi.fi/display/kumea/Loppupisteohje is implemented via another validator/fixer (ending-punctuation).\n* This file has some support but it's now yet thorough. (And mmight never be.)\n* NOTE #2: Validator/fixer punctuation does similar stuff, but focuses on X00 fields.\n* NOTE #3: As of 2023-06-05 control subfields ($0...$9) are obsolete. Don't use them in rules.\n* (They are jumped over when looking for next (non-controlfield subfield)\n*/\nimport {validateSingleField} from './ending-punctuation.js';\nimport {fieldGetUnambiguousTag} from './subfield6Utils.js';\n//import createDebugLogger from 'debug';\nimport {fieldToString, nvdebug} from './utils.js';\nimport clone from 'clone';\n\n//const debug = createDebugLogger('debug/punctuation2');\n\nconst descriptionString = 'Remove invalid and add valid punctuation to data fields';\nexport default function () {\n return {\n description: descriptionString,\n validate, fix\n };\n\n function fix(record) {\n nvdebug(`${descriptionString}: fixer`);\n const res = {message: [], fix: [], valid: true};\n record.fields.forEach(f => fieldFixPunctuation(f));\n return res;\n }\n\n function validate(record) {\n nvdebug(`${descriptionString}: validate`);\n\n const fieldsNeedingModification = record.fields.filter(f => fieldNeedsModification(f, true));\n\n\n const values = fieldsNeedingModification.map(f => fieldToString(f));\n const newValues = fieldsNeedingModification.map(f => fieldGetFixedString(f, true));\n\n const messages = values.map((val, i) => `'${val}' => '${newValues[i]}'`);\n\n const res = {message: messages};\n\n res.valid = res.message.length < 1;\n return res;\n }\n}\n\nfunction isControlSubfield(subfield) {\n return ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(subfield.code);\n}\n\nfunction getNextRelevantSubfield(field, currSubfieldIndex) {\n return field.subfields.find((subfield, index) => index > currSubfieldIndex && !isControlSubfield(subfield));\n}\n\nexport function fieldGetFixedString(field, add = true) {\n const cloneField = clone(field);\n const operation = add ? subfieldFixPunctuation : subfieldStripPunctuation;\n cloneField.subfields.forEach((sf, i) => {\n // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!\n // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)\n operation(cloneField, sf, getNextRelevantSubfield(cloneField, i));\n });\n return fieldToString(cloneField);\n}\n\nexport function fieldNeedsModification(field, add = true) {\n if (!field.subfields) {\n return false;\n }\n\n const originalFieldAsString = fieldToString(field);\n const modifiedFieldAsString = fieldGetFixedString(field, add);\n\n return modifiedFieldAsString !== originalFieldAsString;\n}\n\n/////////////////////////////////////////////////////////////////////////////////////\n// <= Above code is written for the validator logic <= //\n// => Everything below was originally transferred from reducers' punctuation.js => //\n/////////////////////////////////////////////////////////////////////////////////////\n\n\n//const stripCrap = / *[-;:,+]+$/u;\nconst needsPuncAfterAlphanumeric = /(?:[a-z0-9A-Z]|\u00E5|\u00E4|\u00F6|\u00C5|\u00C4|\u00D6)$/u;\nconst defaultNeedsPuncAfter2 = /(?:[\\]a-zA-Z0-9)]|\u00E4|\u00E5|\u00F6|\u00C5|\u00C4|\u00D6)$/u;\nconst doesNotEndInPunc = /[^!?.:;,]$/u; // non-punc for pre-240/700/XXX $, note that '.' comes if preceded by ')'\nconst blocksPuncRHS = /^(?:\\()/u;\nconst allowsPuncRHS = /^(?:[A-Za-z0-9]|\u00E5|\u00E4|\u00F6|\u00C5|\u00C4|\u00D6)/u;\nconst aToZ = 'abcdefghijklmnopqrstuvwxyz';\n\n\nconst dotIsProbablyPunc = /(?:[a-z0-9)]|\u00E5|\u00E4|\u00F6|(?:[A-Za-z0-9]|\u00C5|\u00C4|\u00D6)(?:[A-Z]|\u00C5|\u00C4|\u00D6))\\.$/u;\nconst puncIsProbablyPunc = /(?:[a-z0-9)]|\u00E5|\u00E4|\u00F6) ?[.,:;]$/u;\n// NB! 65X: Finnish terms don't use punctuation, but international ones do. Neither one is currently (2021-11-08) coded here.\n\n// Will unfortunately trigger \"Sukunimi, Th.\" type:\nconst removeColons = {'code': 'abcdefghijklmnopqrstuvwxyz', 'remove': / *[;:]$/u};\nconst removeX00Comma = {'code': 'abcdejnqt', 'followedBy': 'abcdenqtv#', 'context': /.,$/u, 'remove': /,$/u};\nconst cleanRHS = {'code': 'abcd', 'followedBy': 'bcde', 'context': /(?:(?:[a-z0-9]|\u00E5|\u00E4|\u00F6)\\.|,)$/u, 'contextRHS': blocksPuncRHS, 'remove': /[.,]$/u};\nconst cleanX00dCommaOrDot = {'code': 'd', 'followedBy': 'et#', 'context': /[0-9]-[,.]$/u, 'remove': /[,.]$/u};\nconst cleanX00aDot = {'code': 'abcde', 'followedBy': 'cdegj', 'context': dotIsProbablyPunc, 'remove': /\\.$/u};\nconst cleanCorruption = {'code': 'abcdefghijklmnopqrstuvwxyz', 'remove': / \\.$/u};\n// These $e dot removals are tricky: before removing the comma, we should know that it ain't an abbreviation such as \"esitt.\"...\nconst cleanX00eDot = {'code': 'e', 'followedBy': 'egj#', 'context': /(?:[ai]ja|j\u00E4)[.,]$/u, 'remove': /\\.$/u};\nconst cleanX11jDot = {'code': 'e', 'followedBy': 'egj#', 'context': /(?:[ai]ja|j\u00E4)[.,]$/u, 'remove': /\\.$/u};\nconst removeCommaBeforeLanguageSubfieldL = {'followedBy': 'l', 'remove': /,$/u};\nconst removeCommaBeforeTitleSubfieldT = {'followedBy': 't', 'remove': /,$/u};\n\nconst X00RemoveDotAfterBracket = {'code': 'cq', 'context': /\\)\\.$/u, 'remove': /\\.$/u};\n// 390, 800, 810, 830...\nconst cleanPuncBeforeLanguage = {'code': 'atvxyz', 'followedBy': 'l', 'context': puncIsProbablyPunc, 'remove': / *[.,:;]$/u};\n\nconst addX00aComma = {'add': ',', 'code': 'abcqej', 'followedBy': 'cdeg', 'context': doesNotEndInPunc, 'contextRHS': allowsPuncRHS};\nconst addX00dComma = {'name': 'X00$d ending in \"-\" does not get comma', 'add': ',', 'code': 'd', 'followedBy': 'cdeg', 'context': /[^-,.!]$/u, 'contextRHS': allowsPuncRHS};\nconst addX00aComma2 = {'add': ',', 'code': 'abcdej', 'followedBy': 'cdeg', 'context': /(?:[A-Z]|\u00C5|\u00C4|\u00D6)\\.$/u, 'contextRHS': allowsPuncRHS};\nconst addX00Dot = {'add': '.', 'code': 'abcdetv', 'followedBy': 'fklptu', 'context': needsPuncAfterAlphanumeric};\nconst addEntryFieldFinalDot = {'name': 'X00 final dot', 'add': '.', 'code': 'abcdefghijklmnopqrstuvwxyz', 'followedBy': '#', 'context': /[^.)!?-]$/u};\n\n\nconst addX10iColon = {name: 'Punctuate relationship information', add: ':', code: 'i', context: defaultNeedsPuncAfter2};\nconst addX10bDot = {'name': 'Add X10 pre-$b dot', 'add': '.', 'code': 'ab', 'followedBy': 'b', 'context': defaultNeedsPuncAfter2};\nconst addX10eComma = {'add': ',', 'code': 'abe', 'followedBy': 'e', 'context': defaultNeedsPuncAfter2};\nconst addX10Dot = {'name': 'Add X10 final dot', 'add': '.', 'code': 'abet', 'followedBy': 'tu#', 'context': needsPuncAfterAlphanumeric};\nconst addColonToRelationshipInformation = {'name': 'Add \\':\\' to 7X0 $i relationship info', 'add': ':', 'code': 'i', 'context': defaultNeedsPuncAfter2};\n\nconst addX11Spacecolon = {name: '611 space colon(y :-)', add: ' :', code: 'nd', followedBy: 'dc', 'context': defaultNeedsPuncAfter2};\n\nconst addDotBeforeLanguageSubfieldL = {'name': 'Add dot before $l', 'add': '.', 'code': 'abepst', 'followedBy': 'l', 'context': doesNotEndInPunc};\n\n// 490:\nconst addSemicolonBeforeVolumeDesignation = {'name': 'Add \" ;\" before $v', 'add': ' ;', 'code': 'atxyz', 'followedBy': 'v', 'context': /[^;]$/u};\n\nconst NONE = 0;\nconst ADD = 2;\nconst REMOVE = 1;\nconst REMOVE_AND_ADD = 3;\n\n// Crappy punctuation consists of various crap that is somewhat common.\n// We strip crap for merge decisions. We are not trying to actively remove crap here.\n\nconst removeCrapFromAllEntryFields = [removeCommaBeforeLanguageSubfieldL, removeCommaBeforeTitleSubfieldT];\n\nconst removeX00Whatever = [removeX00Comma, cleanX00aDot, cleanX00eDot, cleanCorruption, cleanX00dCommaOrDot, cleanRHS, X00RemoveDotAfterBracket, removeColons, cleanPuncBeforeLanguage, ...removeCrapFromAllEntryFields];\nconst removeX10Whatever = [removeX00Comma, cleanX00aDot, cleanX00eDot, cleanCorruption, removeColons, cleanPuncBeforeLanguage, ...removeCrapFromAllEntryFields];\nconst removeX11Whatever = [removeX00Comma, cleanX11jDot, ...removeCrapFromAllEntryFields];\nconst removeX30Whatever = removeCrapFromAllEntryFields;\n\nconst remove490And830Whatever = [{'code': 'axyzv', 'followedBy': 'axyzv', 'remove': /(?: *;| *=|,)$/u}];\n\nconst linkingEntryRemoveWhatever = [\n {'code': 'i', 'followedBy': 'at', 'remove': / ?:$/u}, // ':'\n {'code': 'at', 'remove': /\\.$/u},\n {'code': 'abdghiklmnopqrstuwxyz', 'followedBy': 'abdghiklmnopqrstuwxyz', 'remove': /\\. -$/u}\n];\n\n\n// '!' means negation, thus '!b' means any other subfield but 'b'.\n// 'followedBy': '#' means that current subfield is the last subfield.\n// NB! Note that control subfields are ignored in punctuation rules.\n// NB #2! Control field ignorance causes issues with field 257: https://wiki.helsinki.fi/display/rdasovellusohje/Loppupisteohje\n// Might need to work on that at some point. NOT a top priority though.\n// NB #3! Final punctuation creation is/should be handled by endind-punctuation.js validator!\n\nconst crappy24X = [\n {'code': 'abnp', 'followedBy': '!c', 'remove': / \\/$/u},\n {'code': 'abn', 'followedBy': 'c', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'abn', 'followedBy': 'c', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'abc', 'followedBy': '#', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'abfghinp', 'followedBy': '#', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'n', 'followedBy': 'p', 'remove': /\\.$/u, 'context': dotIsProbablyPunc}, // MELINDA-8817\n {'code': 'p', 'followedBy': 'pc', 'remove': /\\.$/u, 'context': dotIsProbablyPunc}, // MELINDA-8817\n removeCommaBeforeLanguageSubfieldL\n];\n\n\nconst cleanCrappyPunctuationRules = {\n '100': removeX00Whatever,\n '110': removeX10Whatever,\n '111': removeX11Whatever,\n '130': removeX30Whatever,\n '240': crappy24X,\n '245': crappy24X,\n '246': crappy24X,\n '300': [\n {'code': 'a', 'followedBy': '!b', 'remove': / *:$/u},\n {'code': 'a', 'followedBy': 'b', 'remove': /:$/u, 'context': /[^ ]:$/u},\n {'code': 'ab', 'followedBy': '!c', 'remove': / *;$/u},\n {'code': 'ab', 'followedBy': 'c', 'remove': /;$/u, 'context': /[^ ];$/u},\n {'code': 'abc', 'followedBy': '!e', 'remove': / *\\+$/u} // Removes both valid (with one space) and invalid (spaceless et al) puncs\n\n ],\n\n '490': remove490And830Whatever,\n '600': removeX00Whatever,\n '610': removeX10Whatever,\n '611': removeX11Whatever,\n '630': removeX30Whatever,\n '700': removeX00Whatever,\n '710': removeX10Whatever,\n '711': removeX11Whatever,\n '730': removeX30Whatever,\n '773': linkingEntryRemoveWhatever,\n '774': linkingEntryRemoveWhatever,\n '776': linkingEntryRemoveWhatever,\n '787': linkingEntryRemoveWhatever,\n '800': removeX00Whatever,\n '810': removeX10Whatever,\n '830': remove490And830Whatever,\n '946': crappy24X\n};\n\nconst cleanLegalX00Comma = {'code': 'abcde', 'followedBy': 'cdegj', 'context': /.,$/u, 'remove': /,$/u};\n// Accept upper case letters in X00$b, since they are probably Roman numerals.\nconst cleanLegalX00bDot = {'code': 'b', 'followedBy': 't#', context: /^[IVXLCDM]+\\.$/u, 'remove': /\\.$/u};\nconst cleanLegalX00iColon = {'code': 'i', 'followedBy': 'a', 'remove': / *:$/u}; // NB! context is not needed\nconst cleanLegalX00Dot = {'code': 'abcdetvl', 'followedBy': 'tu#', 'context': /(?:[a-z0-9)]|\u00E5|\u00E4|\u00F6)\\.$/u, 'remove': /\\.$/u};\nconst cleanDotBeforeLanguageSubfieldL = {'name': 'pre-language-$l dot', 'followedBy': 'l', 'context': /.\\.$/u, 'remove': /\\.$/u};\n\nconst legalEntryField = [cleanDotBeforeLanguageSubfieldL];\n\nconst legalX11SpaceColon = {name: 'legal X11 spacecolony', code: 'nd', followedBy: 'dc', context: / :$/u, remove: / :$/u};\nconst legalX00punc = [cleanLegalX00Comma, cleanLegalX00iColon, cleanLegalX00bDot, cleanLegalX00Dot, ...legalEntryField];\n\nconst cleanLegalX10Comma = {'name': 'X10comma', 'code': 'abe', 'followedBy': 'e', 'context': /.,$/u, 'remove': /,$/u};\nconst cleanLegalX10Dot = {'name': 'X10dot', 'code': 'abt', 'followedBy': 'bst#', 'context': /.\\.$/u, 'remove': /\\.$/u};\n\nconst legalX10punc = [cleanLegalX10Comma, cleanLegalX10Dot, cleanX00eDot, ...legalEntryField];\n\nconst cleanLegalSeriesTitle = [ // 490 and 830\n {'code': 'a', 'followedBy': 'a', 'remove': / =$/u},\n {'code': 'axyz', 'followedBy': 'xyz', 'remove': /,$/u, 'context': /.,$/u},\n {'code': 'axyz', 'followedBy': 'v', 'remove': / *;$/u}\n];\n\nconst clean24X = [\n {'name': 'I:A', 'code': 'i', 'followedBy': 'a', 'remove': / *:$/u},\n {'name': 'A:B', 'code': 'a', 'followedBy': 'b', 'remove': / [:;=]$/u},\n {'name': 'AB:K', 'code': 'ab', 'followedBy': 'k', 'remove': / :$/u},\n {'name': 'ABK:F', 'code': 'abk', 'followedBy': 'f', 'remove': /,$/u},\n {'name': 'ABFNP:C', 'code': 'abfnp', 'followedBy': 'c', 'remove': / \\/$/u},\n {'name': 'ABN:N', 'code': 'abn', 'followedBy': 'n', 'remove': /\\.$/u},\n {'name': 'ABNP:#', 'code': 'abnp', 'followedBy': '#', 'remove': /\\.$/u},\n {'name': 'N:P', 'code': 'n', 'followedBy': 'p', 'remove': /,$/u},\n cleanDotBeforeLanguageSubfieldL\n];\n\nconst legalX11Punc = [...legalEntryField, legalX11SpaceColon];\n\nconst cleanValidPunctuationRules = {\n '100': legalX00punc,\n '110': legalX10punc,\n '111': legalX11Punc,\n '130': legalEntryField,\n '240': clean24X,\n '243': clean24X,\n '245': clean24X,\n '246': clean24X,\n '260': [\n {'code': 'abc', 'followedBy': 'a', 'remove': / ;$/u},\n {'code': 'a', 'followedBy': 'b', 'remove': / :$/u},\n {'code': 'b', 'followedBy': 'c', 'remove': /,$/u},\n {'code': 'c', 'followedBy': '#', 'remove': /\\.$/u},\n {'code': 'd', 'followedBy': 'e', 'remove': / :$/u},\n {'code': 'e', 'followedBy': 'f', 'remove': /,$/u},\n {'code': 'f', 'followedBy': '#', 'remove': /\\.$/u} // Probably ')' but should it be removed?\n ],\n '264': [\n {'code': 'a', 'followedBy': 'b', 'remove': / :$/u},\n {'code': 'b', 'followedBy': 'c', 'remove': /,$/u},\n {'code': 'c', 'followedBy': '#', 'remove': /\\.$/u}\n ],\n '300': [\n // NB! Remove crap as well, thus the '*' in / *:$/\n {'code': 'a', 'followedBy': 'b', 'remove': / :$/u},\n {'code': 'ab', 'followedBy': 'c', 'remove': / ;$/u},\n {'code': 'abc', 'followedBy': 'e', 'remove': / \\+$/u}\n ],\n '490': cleanLegalSeriesTitle,\n '534': [{'code': 'p', 'followedBy': 'c', 'remove': /:$/u}],\n '600': legalX00punc,\n '610': legalX10punc,\n '611': legalX11Punc,\n '630': legalEntryField,\n // Experimental, MET366-ish (end punc in internationally valid, but we don't use it here in Finland):\n '648': [{'code': 'a', 'content': /^[0-9]+\\.$/u, 'ind2': ['4'], 'remove': /\\.$/u}],\n '700': legalX00punc,\n '710': legalX10punc,\n '711': legalX11Punc,\n '730': legalEntryField,\n '800': legalX00punc,\n '810': legalX10punc,\n '811': legalX11Punc,\n '830': [...legalEntryField, ...cleanLegalSeriesTitle],\n '946': clean24X\n};\n\n\n// Overgeneralizes a bit: eg. addColonToRelationshipInformation only applies to 700/710 but as others don't have $i, it's fine.\nconst addToAllEntryFields = [addDotBeforeLanguageSubfieldL, addSemicolonBeforeVolumeDesignation, addColonToRelationshipInformation, addEntryFieldFinalDot];\n\n\nconst addX00 = [addX00aComma, addX00aComma2, addX00Dot, addX00dComma, ...addToAllEntryFields];\nconst addX10 = [addX10iColon, addX10bDot, addX10eComma, addX10Dot, ...addToAllEntryFields];\nconst addX11 = [...addToAllEntryFields, addX11Spacecolon];\nconst addX30 = [...addToAllEntryFields];\n\nconst add24X = [\n {'code': 'i', 'followedBy': 'a', 'add': ':', 'context': needsPuncAfterAlphanumeric},\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': '[^:]$'},\n {'code': 'abk', 'followedBy': 'f', 'add': ',', 'context': needsPuncAfterAlphanumeric},\n {'code': 'abfnp', 'followedBy': 'c', 'add': ' /', 'context': '[^/]$'},\n addDotBeforeLanguageSubfieldL\n];\n\nconst add245 = [\n ...add24X,\n // Blah! Also \"$a = $b\" and \"$a ; $b\" can be valid... But ' :' is better than nothing, I guess...\n {'code': 'ab', 'followedBy': 'n', 'add': '.', 'context': needsPuncAfterAlphanumeric},\n {'code': 'n', 'followedBy': 'p', 'add': ',', 'context': defaultNeedsPuncAfter2},\n {'code': 'abnpc', 'followedBy': '#', 'add': '.', 'context': needsPuncAfterAlphanumeric} // Stepping on \"punctuation validator's\" toes\n];\n\nconst addSeriesTitle = [ // 490 and 830\n {'code': 'a', 'followedBy': 'a', 'add': ' =', 'context': defaultNeedsPuncAfter2},\n {'code': 'axyz', 'followedBy': 'xy', 'add': ',', 'context': defaultNeedsPuncAfter2},\n addSemicolonBeforeVolumeDesignation // eg. 490$axyz-$v\n];\n\nconst addLinkingEntry = [ // NB! Music 773 uses different punctuation rules, that are not implement here (can they even be?)\n {'code': 'i', 'followedBy': aToZ, 'add': ':', 'context': defaultNeedsPuncAfter2},\n {'code': 'a', 'followedBy': 't', 'add': '.', 'context': defaultNeedsPuncAfter2},\n {'code': 't', 'followedBy': 'dghoz', 'add': '.', 'context': defaultNeedsPuncAfter2}\n];\n\nconst addPairedPunctuationRules = {\n '100': addX00,\n '110': addX10,\n '111': addX11,\n '130': addX30,\n '240': add24X,\n '243': add24X,\n '245': add245,\n '246': add24X,\n '260': [\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'ab', 'followedBy': 'c', 'add': ',', 'context': defaultNeedsPuncAfter2},\n {'code': 'abc', 'followedBy': 'a', 'add': ' ;', 'context': defaultNeedsPuncAfter2},\n {'code': 'e', 'followedBy': 'f', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'f', 'followedBy': 'g', 'add': ',', 'context': defaultNeedsPuncAfter2}\n ],\n '264': [\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'b', 'followedBy': 'c', 'add': ',', 'context': defaultNeedsPuncAfter2},\n // NB! The $c rule messes dotless exception \"264 #4 $c p1983\" up\n // We'll need to add a hacky postprocessor for this? Add 'hasInd1': '0123' etc?\n {'code': 'c', 'followedBy': '#', 'add': '.', 'context': needsPuncAfterAlphanumeric, 'ind2': ['0', '1', '2', '3']}\n ],\n '300': [\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'ab', 'followedBy': 'c', 'add': ' ;', 'context': defaultNeedsPuncAfter2},\n {'code': 'abc', 'followedBy': 'e', 'add': ' +', 'context': defaultNeedsPuncAfter2}\n ],\n '490': addSeriesTitle,\n '506': [{'code': 'a', 'followedBy': '#', 'add': '.', 'context': defaultNeedsPuncAfter2}],\n '534': [{'code': 'p', 'followedBy': 'c', 'add': ':', 'context': defaultNeedsPuncAfter2}],\n '600': addX00,\n '610': addX10,\n '611': addX11,\n '630': addX30,\n '700': addX00,\n '710': addX10,\n '711': addX11,\n '730': addX30,\n '773': addLinkingEntry,\n '787': addLinkingEntry,\n '800': addX00,\n '810': addX10,\n '811': addX11,\n '830': [...addX30, ...addSeriesTitle],\n '946': [{'code': 'i', 'followedBy': 'a', 'add': ':', 'context': defaultNeedsPuncAfter2}]\n};\n\n/*\nfunction debugRule(rule) {\n //nvdebug('');\n nvdebug(`NAME ${rule.name ? rule.name : '<unnamed>'}`);\n nvdebug(`SUBFIELD CODE '${rule.code}' FOLLOWED BY SUBFIELD CODE '${rule.followedBy}'`);\n if ('add' in rule) {\n nvdebug(`ADD '${rule.add}'`);\n }\n if ('remove' in rule) {\n nvdebug(`REMOVE '${rule.remove}'`);\n }\n if ('context' in rule) {\n nvdebug(`CONTEXT '${rule.context.toString()}'`);\n }\n //nvdebug('');\n}\n*/\n\nfunction ruleAppliesToSubfieldCode(targetSubfieldCodes, currSubfieldCode) {\n if (!targetSubfieldCodes) { // We are not interested in what subfield precedes 240$l, ',' is removed anyway\n return true;\n }\n const negation = targetSubfieldCodes.includes('!');\n if (negation) {\n return !targetSubfieldCodes.includes(currSubfieldCode);\n }\n return targetSubfieldCodes.includes(currSubfieldCode);\n}\n\n\nfunction ruleAppliesToField(rule, field) {\n if ('ind1' in rule && !rule.ind1.includes(field.ind1)) {\n return false;\n }\n\n if ('ind2' in rule && !rule.ind2.includes(field.ind2)) {\n return false;\n }\n\n // If we want to check, say, $2, it should be implemented here!\n\n return true;\n}\n\n\nfunction ruleAppliesToCurrentSubfield(rule, subfield) {\n //nvdebug(` Apply rule on LHS?`);\n if (!ruleAppliesToSubfieldCode(rule.code, subfield.code)) {\n //nvdebug(` Reject rule!`);\n return false;\n }\n if ('context' in rule) {\n //nvdebug(` Check '${subfield.value}' versus '${rule.context.toString()}'`);\n if (!subfield.value.match(rule.context)) { // njsscan-ignore: regex_injection_dos\n //nvdebug(` Reject rule!`);\n return false;\n }\n }\n //nvdebug(` Apply rule!`);\n return true;\n}\n\nfunction ruleAppliesToNextSubfield(rule, nextSubfield) {\n if (!('followedBy' in rule)) { // Return true, if we are not interested in the next subfield\n return true;\n }\n // The '#' existence check applies only to the RHS field. LHS always exists.\n if (!nextSubfield) {\n const negation = rule.followedBy.includes('!');\n if (negation) {\n return !rule.followedBy.includes('#');\n }\n return rule.followedBy.includes('#');\n }\n\n if (!ruleAppliesToSubfieldCode(rule.followedBy, nextSubfield.code)) {\n return false;\n }\n if ('contextRHS' in rule && !nextSubfield.value.match(rule.contextRHS)) { // njsscan-ignore: regex_injection_dos\n return false;\n }\n return true;\n}\n\nfunction checkRule(rule, field, subfield1, subfield2) {\n if (!ruleAppliesToField(rule, field)) {\n //nvdebug(`FAIL ON WHOLE FIELD: '${fieldToString(field)}`);\n return false;\n }\n //const name = rule.name || 'UNNAMED';\n if (!ruleAppliesToCurrentSubfield(rule, subfield1)) {\n //nvdebug(`${name}: FAIL ON LHS SUBFIELD: '$${subfield1.code} ${subfield1.value}', SF=${rule.code}`, debug);\n return false;\n }\n\n // NB! This is not a perfect solution. We might have $e$0$e where $e$0 punctuation should actually be based on $e$e rules\n if (!ruleAppliesToNextSubfield(rule, subfield2)) {\n //const msg = subfield2 ? `${name}: FAIL ON RHS SUBFIELD '${subfield2.code}' not in [${rule.followedBy}]` : `${name}: FAIL ON RHS FIELD`;\n //nvdebug(msg, debug);\n return false;\n }\n\n //nvdebug(`${rule.name ? rule.name : '<unnamed>'}: ACCEPT ${rule.code} (${subfield1.code}), SF2=${rule.followedBy} (${subfield2 ? subfield2.code : '#'})`, debug);\n return true;\n}\n\n\nfunction applyPunctuationRules(field, subfield1, subfield2, ruleArray = null, operation = NONE) {\n if (operation === NONE || ruleArray === null) { // !fieldIsApplicable(field, ruleArray)) {\n return;\n }\n const tag2 = field.tag === '880' ? fieldGetUnambiguousTag(field) : field.tag;\n if (!tag2) {\n return;\n }\n if (!(`${tag2}` in ruleArray)) {\n return;\n }\n\n //nvdebug(`PUNCTUATE ${field.tag}/${tag2} '${subfieldToString(subfield1)}' XXX '${subfield2 ? subfieldToString(subfield2) : '#'} }`);\n\n //nvdebug(`OP=${operation} ${tag2}: '${subfield1.code}: ${subfield1.value}' ??? '${subfield2 ? subfield2.code : '#'}'`);\n const candRules = ruleArray[tag2];\n candRules.every(rule => { // uses \"every\", not \"forEach\", so that only one rule is applies to the given subfields\n //debugRule(rule);\n if (!checkRule(rule, field, subfield1, subfield2)) {\n return true;\n }\n\n //const originalValue = subfield1.value;\n if (rule.remove && [REMOVE, REMOVE_AND_ADD].includes(operation) && subfield1.value.match(rule.remove)) {\n //nvdebug(` PUNC REMOVAL TO BE PERFORMED FOR $${subfield1.code} '${subfield1.value}'`, debug);\n subfield1.value = subfield1.value.replace(rule.remove, '');\n //nvdebug(` PUNC REMOVAL PERFORMED FOR '${subfield1.value}'`);\n return false;\n }\n if (rule.add && [ADD, REMOVE_AND_ADD].includes(operation)) {\n subfield1.value += rule.add;\n //nvdebug(` ADDED '${rule.add}' TO FORM '${subfield1.value}' USING RULE ${rule.name}`);\n return false;\n }\n\n /*\n if (subfield1.value !== originalValue) {\n nvdebug(` PROCESS PUNC: '\u2021${subfield1.code} ${originalValue}' => '\u2021${subfield1.code} ${subfield1.value}'`, debug);\n }\n */\n\n return true;\n });\n}\n\nfunction subfieldFixPunctuation(field, subfield1, subfield2) {\n applyPunctuationRules(field, subfield1, subfield2, cleanCrappyPunctuationRules, REMOVE);\n applyPunctuationRules(field, subfield1, subfield2, addPairedPunctuationRules, ADD);\n}\n\nfunction subfieldStripPunctuation(field, subfield1, subfield2) {\n //nvdebug(`FSP1: '${subfield1.value}'`);\n applyPunctuationRules(field, subfield1, subfield2, cleanValidPunctuationRules, REMOVE);\n //nvdebug(`FSP2: '${subfield1.value}'`);\n applyPunctuationRules(field, subfield1, subfield2, cleanCrappyPunctuationRules, REMOVE);\n //nvdebug(`FSP3: '${subfield1.value}'`);\n\n}\n\nexport function fieldStripPunctuation(field) {\n if (!field.subfields) {\n return field;\n }\n\n field.subfields.forEach((sf, i) => {\n // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!\n // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)\n subfieldStripPunctuation(field, sf, getNextRelevantSubfield(field, i));\n\n });\n return field;\n}\n\nexport function fieldFixPunctuation(field) {\n if (!field.subfields) {\n return field;\n }\n //nvdebug(`################### fieldFixPunctuation() TEST ${fieldToString(field)}`);\n\n field.subfields.forEach((sf, i) => {\n // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!\n // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)\n // We'll need some magic for field 257 here, do we? (Also Finnish lexicons vs global lexicons in 65X fields)\n subfieldFixPunctuation(field, sf, getNextRelevantSubfield(field, i));\n });\n\n // Use shared code for final punctuation (sadly this does not fix intermediate punc):\n if (field.useExternalEndPunctuation) {\n // addFinalPunctuation(field); // local version. use shared code instead.\n validateSingleField(field, false, true); // NB! Don't use field.tag as second argument! It's a string, not an int. 3rd arg must be true (=fix)\n }\n return field;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n* punctuation.js -- try and fix a marc field punctuation\n*\n* Author(s): Nicholas Volk <nicholas.volk@helsinki.fi>\n*\n* NOTE #1: https://www.kiwi.fi/display/kumea/Loppupisteohje is implemented via another validator/fixer (ending-punctuation).\n* This file has some support but it's now yet thorough. (And mmight never be.)\n* NOTE #2: Validator/fixer punctuation does similar stuff, but focuses on X00 fields.\n* NOTE #3: As of 2023-06-05 control subfields ($0...$9) are obsolete. Don't use them in rules.\n* (They are jumped over when looking for next (non-controlfield subfield)\n*/\nimport {validateSingleField} from './ending-punctuation.js';\nimport {tagToDataProvenanceSubfieldCode} from './merge-fields/dataProvenance.js';\nimport {fieldGetUnambiguousTag} from './subfield6Utils.js';\n//import createDebugLogger from 'debug';\nimport {fieldToString, isControlSubfieldCode, nvdebug} from './utils.js';\nimport clone from 'clone';\n\n//const debug = createDebugLogger('debug/punctuation2');\n\nconst descriptionString = 'Remove invalid and add valid punctuation to data fields';\nexport default function () {\n return {\n description: descriptionString,\n validate, fix\n };\n\n function fix(record) {\n nvdebug(`${descriptionString}: fixer`);\n const res = {message: [], fix: [], valid: true};\n record.fields.forEach(f => fieldFixPunctuation(f));\n return res;\n }\n\n function validate(record) {\n nvdebug(`${descriptionString}: validate`);\n\n const fieldsNeedingModification = record.fields.filter(f => fieldNeedsModification(f, true));\n\n\n const values = fieldsNeedingModification.map(f => fieldToString(f));\n const newValues = fieldsNeedingModification.map(f => fieldGetFixedString(f, true));\n\n const messages = values.map((val, i) => `'${val}' => '${newValues[i]}'`);\n\n const res = {message: messages};\n\n res.valid = res.message.length < 1;\n return res;\n }\n}\n\n\n\nfunction isIrrelevantSubfield(subfield, tag) {\n const dataProvenanceSubfieldCode = tagToDataProvenanceSubfieldCode(tag);\n if (subfield.code === dataProvenanceSubfieldCode) {\n return true;\n }\n return isControlSubfieldCode(subfield.code); // Currently this contains other stuff as well ($3, $4, $7, $9...)\n}\n\n\nfunction getNextRelevantSubfield(field, currSubfieldIndex) {\n return field.subfields.find((subfield, index) => index > currSubfieldIndex && !isIrrelevantSubfield(subfield, field.tag));\n}\n\nexport function fieldGetFixedString(field, add = true) {\n const cloneField = clone(field);\n const operation = add ? subfieldFixPunctuation : subfieldStripPunctuation;\n cloneField.subfields.forEach((sf, i) => {\n // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!\n // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)\n operation(cloneField, sf, getNextRelevantSubfield(cloneField, i));\n });\n return fieldToString(cloneField);\n}\n\nexport function fieldNeedsModification(field, add = true) {\n if (!field.subfields) {\n return false;\n }\n\n const originalFieldAsString = fieldToString(field);\n const modifiedFieldAsString = fieldGetFixedString(field, add);\n\n return modifiedFieldAsString !== originalFieldAsString;\n}\n\n/////////////////////////////////////////////////////////////////////////////////////\n// <= Above code is written for the validator logic <= //\n// => Everything below was originally transferred from reducers' punctuation.js => //\n/////////////////////////////////////////////////////////////////////////////////////\n\n\n//const stripCrap = / *[-;:,+]+$/u;\nconst needsPuncAfterAlphanumeric = /(?:[a-z0-9A-Z]|\u00E5|\u00E4|\u00F6|\u00C5|\u00C4|\u00D6)$/u;\nconst defaultNeedsPuncAfter2 = /(?:[\\]a-zA-Z0-9)]|\u00E4|\u00E5|\u00F6|\u00C5|\u00C4|\u00D6)$/u;\nconst doesNotEndInPunc = /[^!?.:;,]$/u; // non-punc for pre-240/700/XXX $, note that '.' comes if preceded by ')'\nconst blocksPuncRHS = /^(?:\\()/u;\nconst allowsPuncRHS = /^(?:[A-Za-z0-9]|\u00E5|\u00E4|\u00F6|\u00C5|\u00C4|\u00D6)/u;\nconst aToZ = 'abcdefghijklmnopqrstuvwxyz';\n\n\nconst dotIsProbablyPunc = /(?:[a-z0-9)]|\u00E5|\u00E4|\u00F6|(?:[A-Za-z0-9]|\u00C5|\u00C4|\u00D6)(?:[A-Z]|\u00C5|\u00C4|\u00D6))\\.$/u;\nconst puncIsProbablyPunc = /(?:[a-z0-9)]|\u00E5|\u00E4|\u00F6) ?[.,:;]$/u;\n// NB! 65X: Finnish terms don't use punctuation, but international ones do. Neither one is currently (2021-11-08) coded here.\n\n// Will unfortunately trigger \"Sukunimi, Th.\" type:\nconst removeColons = {'code': 'abcdefghijklmnopqrstuvwxyz', 'remove': / *[;:]$/u};\nconst removeX00Comma = {'code': 'abcdejnqt', 'followedBy': 'abcdenqtv#', 'context': /.,$/u, 'remove': /,$/u};\nconst cleanRHS = {'code': 'abcd', 'followedBy': 'bcde', 'context': /(?:(?:[a-z0-9]|\u00E5|\u00E4|\u00F6)\\.|,)$/u, 'contextRHS': blocksPuncRHS, 'remove': /[.,]$/u};\nconst cleanX00dCommaOrDot = {'code': 'd', 'followedBy': 'et#', 'context': /[0-9]-[,.]$/u, 'remove': /[,.]$/u};\nconst cleanX00aDot = {'code': 'abcde', 'followedBy': 'cdegj', 'context': dotIsProbablyPunc, 'remove': /\\.$/u};\nconst cleanCorruption = {'code': 'abcdefghijklmnopqrstuvwxyz', 'remove': / \\.$/u};\n// These $e dot removals are tricky: before removing the comma, we should know that it ain't an abbreviation such as \"esitt.\"...\nconst cleanX00eDot = {'code': 'e', 'followedBy': 'egj#', 'context': /(?:[ai]ja|j\u00E4)[.,]$/u, 'remove': /\\.$/u};\nconst cleanX11jDot = {'code': 'e', 'followedBy': 'egj#', 'context': /(?:[ai]ja|j\u00E4)[.,]$/u, 'remove': /\\.$/u};\nconst removeCommaBeforeLanguageSubfieldL = {'followedBy': 'l', 'remove': /,$/u};\nconst removeCommaBeforeTitleSubfieldT = {'followedBy': 't', 'remove': /,$/u};\n\nconst X00RemoveDotAfterBracket = {'code': 'cq', 'context': /\\)\\.$/u, 'remove': /\\.$/u};\n// 390, 800, 810, 830...\nconst cleanPuncBeforeLanguage = {'code': 'atvxyz', 'followedBy': 'l', 'context': puncIsProbablyPunc, 'remove': / *[.,:;]$/u};\n\nconst addX00aComma = {'add': ',', 'code': 'abcqej', 'followedBy': 'cdeg', 'context': doesNotEndInPunc, 'contextRHS': allowsPuncRHS};\nconst addX00dComma = {'name': 'X00$d ending in \"-\" does not get comma', 'add': ',', 'code': 'd', 'followedBy': 'cdeg', 'context': /[^-,.!]$/u, 'contextRHS': allowsPuncRHS};\nconst addX00aComma2 = {'add': ',', 'code': 'abcdej', 'followedBy': 'cdeg', 'context': /(?:[A-Z]|\u00C5|\u00C4|\u00D6)\\.$/u, 'contextRHS': allowsPuncRHS};\nconst addX00Dot = {'add': '.', 'code': 'abcdetv', 'followedBy': 'fklptu', 'context': needsPuncAfterAlphanumeric};\nconst addEntryFieldFinalDot = {'name': 'X00 final dot', 'add': '.', 'code': 'abcdefghijklmnopqrstuvwxyz', 'followedBy': '#', 'context': /[^.)!?-]$/u};\n\n\nconst addX10iColon = {name: 'Punctuate relationship information', add: ':', code: 'i', context: defaultNeedsPuncAfter2};\nconst addX10bDot = {'name': 'Add X10 pre-$b dot', 'add': '.', 'code': 'ab', 'followedBy': 'b', 'context': defaultNeedsPuncAfter2};\nconst addX10eComma = {'add': ',', 'code': 'abe', 'followedBy': 'e', 'context': defaultNeedsPuncAfter2};\nconst addX10Dot = {'name': 'Add X10 final dot', 'add': '.', 'code': 'abet', 'followedBy': 'tu#', 'context': needsPuncAfterAlphanumeric};\nconst addColonToRelationshipInformation = {'name': 'Add \\':\\' to 7X0 $i relationship info', 'add': ':', 'code': 'i', 'context': defaultNeedsPuncAfter2};\n\nconst addX11Spacecolon = {name: '611 space colon(y :-)', add: ' :', code: 'nd', followedBy: 'dc', 'context': defaultNeedsPuncAfter2};\n\nconst addDotBeforeLanguageSubfieldL = {'name': 'Add dot before $l', 'add': '.', 'code': 'abepst', 'followedBy': 'l', 'context': doesNotEndInPunc};\n\n// 490:\nconst addSemicolonBeforeVolumeDesignation = {'name': 'Add \" ;\" before $v', 'add': ' ;', 'code': 'atxyz', 'followedBy': 'v', 'context': /[^;]$/u};\n\nconst NONE = 0;\nconst ADD = 2;\nconst REMOVE = 1;\nconst REMOVE_AND_ADD = 3;\n\n// Crappy punctuation consists of various crap that is somewhat common.\n// We strip crap for merge decisions. We are not trying to actively remove crap here.\n\nconst removeCrapFromAllEntryFields = [removeCommaBeforeLanguageSubfieldL, removeCommaBeforeTitleSubfieldT];\n\nconst removeX00Whatever = [removeX00Comma, cleanX00aDot, cleanX00eDot, cleanCorruption, cleanX00dCommaOrDot, cleanRHS, X00RemoveDotAfterBracket, removeColons, cleanPuncBeforeLanguage, ...removeCrapFromAllEntryFields];\nconst removeX10Whatever = [removeX00Comma, cleanX00aDot, cleanX00eDot, cleanCorruption, removeColons, cleanPuncBeforeLanguage, ...removeCrapFromAllEntryFields];\nconst removeX11Whatever = [removeX00Comma, cleanX11jDot, ...removeCrapFromAllEntryFields];\nconst removeX30Whatever = removeCrapFromAllEntryFields;\n\nconst remove490And830Whatever = [{'code': 'axyzv', 'followedBy': 'axyzv', 'remove': /(?: *;| *=|,)$/u}];\n\nconst linkingEntryRemoveWhatever = [\n {'code': 'i', 'followedBy': 'at', 'remove': / ?:$/u}, // ':'\n {'code': 'at', 'remove': /\\.$/u},\n // Only \". -\" separator is still used in music. We can strip it, but can only create the non-music punctuation!\n {'code': 'abdghiklmnopqrstuwxyz', 'followedBy': 'abdghiklmnopqrstuwxyz#', 'remove': /\\. -$/u}\n];\n\n\n// '!' means negation, thus '!b' means any other subfield but 'b'.\n// 'followedBy': '#' means that current subfield is the last subfield.\n// NB! Note that control subfields are ignored in punctuation rules.\n// NB #2! Control field ignorance causes issues with field 257: https://wiki.helsinki.fi/display/rdasovellusohje/Loppupisteohje\n// Might need to work on that at some point. NOT a top priority though.\n// NB #3! Final punctuation creation is/should be handled by endind-punctuation.js validator!\n\nconst crappy24X = [\n {'code': 'abnp', 'followedBy': '!c', 'remove': / \\/$/u},\n {'code': 'abn', 'followedBy': 'c', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'abn', 'followedBy': 'c', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'abc', 'followedBy': '#', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'abfghinp', 'followedBy': '#', 'remove': /\\.$/u, 'context': dotIsProbablyPunc},\n {'code': 'n', 'followedBy': 'p', 'remove': /\\.$/u, 'context': dotIsProbablyPunc}, // MELINDA-8817\n {'code': 'p', 'followedBy': 'pc', 'remove': /\\.$/u, 'context': dotIsProbablyPunc}, // MELINDA-8817\n removeCommaBeforeLanguageSubfieldL\n];\n\n\nconst cleanCrappyPunctuationRules = {\n '100': removeX00Whatever,\n '110': removeX10Whatever,\n '111': removeX11Whatever,\n '130': removeX30Whatever,\n '240': crappy24X,\n '245': crappy24X,\n '246': crappy24X,\n '300': [\n {'code': 'a', 'followedBy': '!b', 'remove': / *:$/u},\n {'code': 'a', 'followedBy': 'b', 'remove': /:$/u, 'context': /[^ ]:$/u},\n {'code': 'ab', 'followedBy': '!c', 'remove': / *;$/u},\n {'code': 'ab', 'followedBy': 'c', 'remove': /;$/u, 'context': /[^ ];$/u},\n {'code': 'abc', 'followedBy': '!e', 'remove': / *\\+$/u} // Removes both valid (with one space) and invalid (spaceless et al) puncs\n\n ],\n\n '490': remove490And830Whatever,\n '600': removeX00Whatever,\n '610': removeX10Whatever,\n '611': removeX11Whatever,\n '630': removeX30Whatever,\n '700': removeX00Whatever,\n '710': removeX10Whatever,\n '711': removeX11Whatever,\n '730': removeX30Whatever,\n '773': linkingEntryRemoveWhatever,\n '774': linkingEntryRemoveWhatever,\n '776': linkingEntryRemoveWhatever,\n '787': linkingEntryRemoveWhatever,\n '800': removeX00Whatever,\n '810': removeX10Whatever,\n '830': remove490And830Whatever,\n '946': crappy24X\n};\n\nconst cleanLegalX00Comma = {'code': 'abcde', 'followedBy': 'cdegj', 'context': /.,$/u, 'remove': /,$/u};\n// Accept upper case letters in X00$b, since they are probably Roman numerals.\nconst cleanLegalX00bDot = {'code': 'b', 'followedBy': 't#', context: /^[IVXLCDM]+\\.$/u, 'remove': /\\.$/u};\nconst cleanLegalX00iColon = {'code': 'i', 'followedBy': 'a', 'remove': / *:$/u}; // NB! context is not needed\nconst cleanLegalX00Dot = {'code': 'abcdetvl', 'followedBy': 'tu#', 'context': /(?:[a-z0-9)]|\u00E5|\u00E4|\u00F6)\\.$/u, 'remove': /\\.$/u};\nconst cleanDotBeforeLanguageSubfieldL = {'name': 'pre-language-$l dot', 'followedBy': 'l', 'context': /.\\.$/u, 'remove': /\\.$/u};\n\nconst legalEntryField = [cleanDotBeforeLanguageSubfieldL];\n\nconst legalX11SpaceColon = {name: 'legal X11 spacecolony', code: 'nd', followedBy: 'dc', context: / :$/u, remove: / :$/u};\nconst legalX00punc = [cleanLegalX00Comma, cleanLegalX00iColon, cleanLegalX00bDot, cleanLegalX00Dot, ...legalEntryField];\n\nconst cleanLegalX10Comma = {'name': 'X10comma', 'code': 'abe', 'followedBy': 'e', 'context': /.,$/u, 'remove': /,$/u};\nconst cleanLegalX10Dot = {'name': 'X10dot', 'code': 'abt', 'followedBy': 'bst#', 'context': /.\\.$/u, 'remove': /\\.$/u};\n\nconst legalX10punc = [cleanLegalX10Comma, cleanLegalX10Dot, cleanX00eDot, ...legalEntryField];\n\nconst cleanLegalSeriesTitle = [ // 490 and 830\n {'code': 'a', 'followedBy': 'a', 'remove': / =$/u},\n {'code': 'axyz', 'followedBy': 'xyz', 'remove': /,$/u, 'context': /.,$/u},\n {'code': 'axyz', 'followedBy': 'v', 'remove': / *;$/u}\n];\n\nconst clean24X = [\n {'name': 'I:A', 'code': 'i', 'followedBy': 'a', 'remove': / *:$/u},\n {'name': 'A:B', 'code': 'a', 'followedBy': 'b', 'remove': / [:;=]$/u},\n {'name': 'AB:K', 'code': 'ab', 'followedBy': 'k', 'remove': / :$/u},\n {'name': 'ABK:F', 'code': 'abk', 'followedBy': 'f', 'remove': /,$/u},\n {'name': 'ABFNP:C', 'code': 'abfnp', 'followedBy': 'c', 'remove': / \\/$/u},\n {'name': 'ABN:N', 'code': 'abn', 'followedBy': 'n', 'remove': /\\.$/u},\n {'name': 'ABNP:#', 'code': 'abnp', 'followedBy': '#', 'remove': /\\.$/u},\n {'name': 'N:P', 'code': 'n', 'followedBy': 'p', 'remove': /,$/u},\n cleanDotBeforeLanguageSubfieldL\n];\n\nconst legalX11Punc = [...legalEntryField, legalX11SpaceColon];\n\nconst cleanValidPunctuationRules = {\n '100': legalX00punc,\n '110': legalX10punc,\n '111': legalX11Punc,\n '130': legalEntryField,\n '240': clean24X,\n '243': clean24X,\n '245': clean24X,\n '246': clean24X,\n '260': [\n {'code': 'abc', 'followedBy': 'a', 'remove': / ;$/u},\n {'code': 'a', 'followedBy': 'b', 'remove': / :$/u},\n {'code': 'b', 'followedBy': 'c', 'remove': /,$/u},\n {'code': 'c', 'followedBy': '#', 'remove': /\\.$/u},\n {'code': 'd', 'followedBy': 'e', 'remove': / :$/u},\n {'code': 'e', 'followedBy': 'f', 'remove': /,$/u},\n {'code': 'f', 'followedBy': '#', 'remove': /\\.$/u} // Probably ')' but should it be removed?\n ],\n '264': [\n {'code': 'a', 'followedBy': 'b', 'remove': / :$/u},\n {'code': 'b', 'followedBy': 'c', 'remove': /,$/u},\n {'code': 'c', 'followedBy': '#', 'remove': /\\.$/u}\n ],\n '300': [\n // NB! Remove crap as well, thus the '*' in / *:$/\n {'code': 'a', 'followedBy': 'b', 'remove': / :$/u},\n {'code': 'ab', 'followedBy': 'c', 'remove': / ;$/u},\n {'code': 'abc', 'followedBy': 'e', 'remove': / \\+$/u}\n ],\n '490': cleanLegalSeriesTitle,\n '534': [{'code': 'p', 'followedBy': 'c', 'remove': /:$/u}],\n '600': legalX00punc,\n '610': legalX10punc,\n '611': legalX11Punc,\n '630': legalEntryField,\n // Experimental, MET366-ish (end punc in internationally valid, but we don't use it here in Finland):\n '648': [{'code': 'a', 'content': /^[0-9]+\\.$/u, 'ind2': ['4'], 'remove': /\\.$/u}],\n '700': legalX00punc,\n '710': legalX10punc,\n '711': legalX11Punc,\n '730': legalEntryField,\n '800': legalX00punc,\n '810': legalX10punc,\n '811': legalX11Punc,\n '830': [...legalEntryField, ...cleanLegalSeriesTitle],\n '946': clean24X\n};\n\n\n// Overgeneralizes a bit: eg. addColonToRelationshipInformation only applies to 700/710 but as others don't have $i, it's fine.\nconst addToAllEntryFields = [addDotBeforeLanguageSubfieldL, addSemicolonBeforeVolumeDesignation, addColonToRelationshipInformation, addEntryFieldFinalDot];\n\n\nconst addX00 = [addX00aComma, addX00aComma2, addX00Dot, addX00dComma, ...addToAllEntryFields];\nconst addX10 = [addX10iColon, addX10bDot, addX10eComma, addX10Dot, ...addToAllEntryFields];\nconst addX11 = [...addToAllEntryFields, addX11Spacecolon];\nconst addX30 = [...addToAllEntryFields];\n\nconst add24X = [\n {'code': 'i', 'followedBy': 'a', 'add': ':', 'context': needsPuncAfterAlphanumeric},\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': '[^:]$'},\n {'code': 'abk', 'followedBy': 'f', 'add': ',', 'context': needsPuncAfterAlphanumeric},\n {'code': 'abfnp', 'followedBy': 'c', 'add': ' /', 'context': '[^/]$'},\n addDotBeforeLanguageSubfieldL\n];\n\nconst add245 = [\n ...add24X,\n // Blah! Also \"$a = $b\" and \"$a ; $b\" can be valid... But ' :' is better than nothing, I guess...\n {'code': 'ab', 'followedBy': 'n', 'add': '.', 'context': needsPuncAfterAlphanumeric},\n {'code': 'n', 'followedBy': 'p', 'add': ',', 'context': defaultNeedsPuncAfter2},\n {'code': 'abnpc', 'followedBy': '#', 'add': '.', 'context': needsPuncAfterAlphanumeric} // Stepping on \"punctuation validator's\" toes\n];\n\nconst addSeriesTitle = [ // 490 and 830\n {'code': 'a', 'followedBy': 'a', 'add': ' =', 'context': defaultNeedsPuncAfter2},\n {'code': 'axyz', 'followedBy': 'xy', 'add': ',', 'context': defaultNeedsPuncAfter2},\n addSemicolonBeforeVolumeDesignation // eg. 490$axyz-$v\n];\n\nconst addLinkingEntry = [ // NB! Music 773 uses different punctuation rules, that are not implement here (can they even be?)\n {'code': 'i', 'followedBy': aToZ, 'add': ':', 'context': defaultNeedsPuncAfter2},\n {'code': 'a', 'followedBy': 't', 'add': '.', 'context': defaultNeedsPuncAfter2},\n {'code': 't', 'followedBy': 'dghoz', 'add': '.', 'context': defaultNeedsPuncAfter2}\n];\n\nconst addPairedPunctuationRules = {\n '100': addX00,\n '110': addX10,\n '111': addX11,\n '130': addX30,\n '240': add24X,\n '243': add24X,\n '245': add245,\n '246': add24X,\n '260': [\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'ab', 'followedBy': 'c', 'add': ',', 'context': defaultNeedsPuncAfter2},\n {'code': 'abc', 'followedBy': 'a', 'add': ' ;', 'context': defaultNeedsPuncAfter2},\n {'code': 'e', 'followedBy': 'f', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'f', 'followedBy': 'g', 'add': ',', 'context': defaultNeedsPuncAfter2}\n ],\n '264': [\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'b', 'followedBy': 'c', 'add': ',', 'context': defaultNeedsPuncAfter2},\n // NB! The $c rule messes dotless exception \"264 #4 $c p1983\" up\n // We'll need to add a hacky postprocessor for this? Add 'hasInd1': '0123' etc?\n {'code': 'c', 'followedBy': '#', 'add': '.', 'context': needsPuncAfterAlphanumeric, 'ind2': ['0', '1', '2', '3']}\n ],\n '300': [\n {'code': 'a', 'followedBy': 'b', 'add': ' :', 'context': defaultNeedsPuncAfter2},\n {'code': 'ab', 'followedBy': 'c', 'add': ' ;', 'context': defaultNeedsPuncAfter2},\n {'code': 'abc', 'followedBy': 'e', 'add': ' +', 'context': defaultNeedsPuncAfter2}\n ],\n '490': addSeriesTitle,\n '506': [{'code': 'a', 'followedBy': '#', 'add': '.', 'context': defaultNeedsPuncAfter2}],\n '534': [{'code': 'p', 'followedBy': 'c', 'add': ':', 'context': defaultNeedsPuncAfter2}],\n '600': addX00,\n '610': addX10,\n '611': addX11,\n '630': addX30,\n '700': addX00,\n '710': addX10,\n '711': addX11,\n '730': addX30,\n '773': addLinkingEntry,\n '787': addLinkingEntry,\n '800': addX00,\n '810': addX10,\n '811': addX11,\n '830': [...addX30, ...addSeriesTitle],\n '946': [{'code': 'i', 'followedBy': 'a', 'add': ':', 'context': defaultNeedsPuncAfter2}]\n};\n\n/*\nfunction debugRule(rule) {\n //nvdebug('');\n nvdebug(`NAME ${rule.name ? rule.name : '<unnamed>'}`);\n nvdebug(`SUBFIELD CODE '${rule.code}' FOLLOWED BY SUBFIELD CODE '${rule.followedBy}'`);\n if ('add' in rule) {\n nvdebug(`ADD '${rule.add}'`);\n }\n if ('remove' in rule) {\n nvdebug(`REMOVE '${rule.remove}'`);\n }\n if ('context' in rule) {\n nvdebug(`CONTEXT '${rule.context.toString()}'`);\n }\n //nvdebug('');\n}\n*/\n\nfunction ruleAppliesToSubfieldCode(targetSubfieldCodes, currSubfieldCode) {\n if (!targetSubfieldCodes) { // We are not interested in what subfield precedes 240$l, ',' is removed anyway\n return true;\n }\n const negation = targetSubfieldCodes.includes('!');\n if (negation) {\n return !targetSubfieldCodes.includes(currSubfieldCode);\n }\n return targetSubfieldCodes.includes(currSubfieldCode);\n}\n\n\nfunction ruleAppliesToField(rule, field) {\n if ('ind1' in rule && !rule.ind1.includes(field.ind1)) {\n return false;\n }\n\n if ('ind2' in rule && !rule.ind2.includes(field.ind2)) {\n return false;\n }\n\n // If we want to check, say, $2, it should be implemented here!\n\n return true;\n}\n\n\nfunction ruleAppliesToCurrentSubfield(rule, subfield) {\n //nvdebug(` Apply rule on LHS?`);\n if (!ruleAppliesToSubfieldCode(rule.code, subfield.code)) {\n //nvdebug(` Reject rule!`);\n return false;\n }\n if ('context' in rule) {\n //nvdebug(` Check '${subfield.value}' versus '${rule.context.toString()}'`);\n if (!subfield.value.match(rule.context)) { // njsscan-ignore: regex_injection_dos\n //nvdebug(` Reject rule!`);\n return false;\n }\n }\n //nvdebug(` Apply rule!`);\n return true;\n}\n\nfunction ruleAppliesToNextSubfield(rule, nextSubfield) {\n if (!('followedBy' in rule)) { // Return true, if we are not interested in the next subfield\n return true;\n }\n // The '#' existence check applies only to the RHS field. LHS always exists.\n if (!nextSubfield) {\n const negation = rule.followedBy.includes('!');\n if (negation) {\n return !rule.followedBy.includes('#');\n }\n return rule.followedBy.includes('#');\n }\n\n if (!ruleAppliesToSubfieldCode(rule.followedBy, nextSubfield.code)) {\n return false;\n }\n if ('contextRHS' in rule && !nextSubfield.value.match(rule.contextRHS)) { // njsscan-ignore: regex_injection_dos\n return false;\n }\n return true;\n}\n\nfunction checkRule(rule, field, subfield1, subfield2) {\n if (!ruleAppliesToField(rule, field)) {\n //nvdebug(`FAIL ON WHOLE FIELD: '${fieldToString(field)}`);\n return false;\n }\n //const name = rule.name || 'UNNAMED';\n if (!ruleAppliesToCurrentSubfield(rule, subfield1)) {\n //nvdebug(`${name}: FAIL ON LHS SUBFIELD: '$${subfield1.code} ${subfield1.value}', SF=${rule.code}`, debug);\n return false;\n }\n\n // NB! This is not a perfect solution. We might have $e$0$e where $e$0 punctuation should actually be based on $e$e rules\n if (!ruleAppliesToNextSubfield(rule, subfield2)) {\n //const msg = subfield2 ? `${name}: FAIL ON RHS SUBFIELD '${subfield2.code}' not in [${rule.followedBy}]` : `${name}: FAIL ON RHS FIELD`;\n //nvdebug(msg, debug);\n return false;\n }\n\n //nvdebug(`${rule.name ? rule.name : '<unnamed>'}: ACCEPT ${rule.code} (${subfield1.code}), SF2=${rule.followedBy} (${subfield2 ? subfield2.code : '#'})`, debug);\n return true;\n}\n\n\nfunction applyPunctuationRules(field, subfield1, subfield2, ruleArray = null, operation = NONE) {\n if (operation === NONE || ruleArray === null) { // !fieldIsApplicable(field, ruleArray)) {\n return;\n }\n const tag2 = field.tag === '880' ? fieldGetUnambiguousTag(field) : field.tag;\n if (!tag2) {\n return;\n }\n if (!(`${tag2}` in ruleArray)) {\n return;\n }\n\n //nvdebug(`PUNCTUATE ${field.tag}/${tag2} '${subfieldToString(subfield1)}' XXX '${subfield2 ? subfieldToString(subfield2) : '#'} }`);\n\n //nvdebug(`OP=${operation} ${tag2}: '${subfield1.code}: ${subfield1.value}' ??? '${subfield2 ? subfield2.code : '#'}'`);\n const candRules = ruleArray[tag2];\n candRules.every(rule => { // uses \"every\", not \"forEach\", so that only one rule is applies to the given subfields\n //debugRule(rule);\n if (!checkRule(rule, field, subfield1, subfield2)) {\n return true;\n }\n\n //const originalValue = subfield1.value;\n if (rule.remove && [REMOVE, REMOVE_AND_ADD].includes(operation) && subfield1.value.match(rule.remove)) {\n //nvdebug(` PUNC REMOVAL TO BE PERFORMED FOR $${subfield1.code} '${subfield1.value}'`, debug);\n subfield1.value = subfield1.value.replace(rule.remove, '');\n //nvdebug(` PUNC REMOVAL PERFORMED FOR '${subfield1.value}'`);\n return false;\n }\n if (rule.add && [ADD, REMOVE_AND_ADD].includes(operation)) {\n subfield1.value += rule.add;\n //nvdebug(` ADDED '${rule.add}' TO FORM '${subfield1.value}' USING RULE ${rule.name}`);\n return false;\n }\n\n /*\n if (subfield1.value !== originalValue) {\n nvdebug(` PROCESS PUNC: '\u2021${subfield1.code} ${originalValue}' => '\u2021${subfield1.code} ${subfield1.value}'`, debug);\n }\n */\n\n return true;\n });\n}\n\nfunction subfieldFixPunctuation(field, subfield1, subfield2) {\n applyPunctuationRules(field, subfield1, subfield2, cleanCrappyPunctuationRules, REMOVE);\n applyPunctuationRules(field, subfield1, subfield2, addPairedPunctuationRules, ADD);\n}\n\nfunction subfieldStripPunctuation(field, subfield1, subfield2) {\n //nvdebug(`FSP1: '${subfield1.value}'`);\n applyPunctuationRules(field, subfield1, subfield2, cleanValidPunctuationRules, REMOVE);\n //nvdebug(`FSP2: '${subfield1.value}'`);\n applyPunctuationRules(field, subfield1, subfield2, cleanCrappyPunctuationRules, REMOVE);\n //nvdebug(`FSP3: '${subfield1.value}'`);\n\n}\n\nexport function fieldStripPunctuation(field) {\n if (!field.subfields) {\n return field;\n }\n\n field.subfields.forEach((sf, i) => {\n // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!\n // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)\n subfieldStripPunctuation(field, sf, getNextRelevantSubfield(field, i));\n\n });\n return field;\n}\n\nexport function fieldFixPunctuation(field) {\n if (!field.subfields) {\n return field;\n }\n //nvdebug(`################### fieldFixPunctuation() TEST ${fieldToString(field)}`);\n\n field.subfields.forEach((sf, i) => {\n // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!\n // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)\n // We'll need some magic for field 257 here, do we? (Also Finnish lexicons vs global lexicons in 65X fields)\n subfieldFixPunctuation(field, sf, getNextRelevantSubfield(field, i));\n });\n\n // Use shared code for final punctuation (sadly this does not fix intermediate punc):\n if (field.useExternalEndPunctuation) {\n // addFinalPunctuation(field); // local version. use shared code instead.\n validateSingleField(field, false, true); // NB! Don't use field.tag as second argument! It's a string, not an int. 3rd arg must be true (=fix)\n }\n return field;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,9 +1,18 @@
1
1
  import assert from "node:assert";
2
- import { MarcRecord } from "@natlibfi/marc-record";
2
+ import createDebugLogger from "debug";
3
+ import fetchMock from "fetch-mock";
3
4
  import validatorFactory from "./translate-terms.js";
5
+ import { MarcRecord } from "@natlibfi/marc-record";
4
6
  import { READERS } from "@natlibfi/fixura";
5
7
  import generateTests from "@natlibfi/fixugen";
6
- import createDebugLogger from "debug";
8
+ import { fakeData } from "../test-fixtures/translate-terms-data.js";
9
+ const uris = [
10
+ "http://www.yso.fi/onto/yso/p13299",
11
+ "http://www.yso.fi/onto/yso/p111739",
12
+ "http://www.yso.fi/onto/yso/p6197061979",
13
+ "http://www.yso.fi/onto/yso/p6196061969",
14
+ "http://urn.fi/URN:NBN:fi:au:slm:s161"
15
+ ];
7
16
  generateTests({
8
17
  callback,
9
18
  path: [import.meta.dirname, "..", "test-fixtures", "translate-terms"],
@@ -14,6 +23,7 @@ generateTests({
14
23
  },
15
24
  hooks: {
16
25
  before: async () => {
26
+ fetchMock.mockGlobal().get(`https://api.finto.fi/rest/v1/data?uri=${uris[0]}&format=application%2Fjson`, { status: 200, headers: {}, body: fakeData }).get(`https://api.finto.fi/rest/v1/data?uri=${uris[1]}&format=application%2Fjson`, { status: 200, headers: {}, body: fakeData }).get(`https://api.finto.fi/rest/v1/data?uri=${uris[2]}&format=application%2Fjson`, { status: 200, headers: {}, body: fakeData }).get(`https://api.finto.fi/rest/v1/data?uri=${uris[3]}&format=application%2Fjson`, { status: 200, headers: {}, body: fakeData }).get(`https://api.finto.fi/rest/v1/data?uri=${uris[4]}&format=application%2Fjson`, { status: 200, headers: {}, body: fakeData });
17
27
  testValidatorFactory();
18
28
  }
19
29
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/translate-terms.test.js"],
4
- "sourcesContent": ["import assert from 'node:assert';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport validatorFactory from './translate-terms.js';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\nimport createDebugLogger from 'debug';\n\ngenerateTests({\n callback,\n path: [import.meta.dirname, '..', 'test-fixtures', 'translate-terms'],\n useMetadataFile: true,\n recurse: false,\n fixura: {\n reader: READERS.JSON\n },\n hooks: {\n before: async () => {\n testValidatorFactory();\n }\n }\n});\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/translate-terms:test');\n\nasync function testValidatorFactory() {\n const validator = await validatorFactory();\n\n assert.equal(typeof validator, 'object');\n assert.equal(typeof validator.description, 'string');\n assert.equal(typeof validator.validate, 'function');\n}\n\nasync function callback({getFixture, enabled = true, fix = false}) {\n if (enabled === false) {\n debug('TEST SKIPPED!');\n return;\n }\n\n const validator = await validatorFactory();\n const record = new MarcRecord(getFixture('record.json'));\n const expectedResult = getFixture('expectedResult.json');\n // console.log(expectedResult); // eslint-disable-line\n\n if (!fix) {\n const result = await validator.validate(record);\n assert.deepEqual(result, expectedResult);\n return;\n }\n\n await validator.fix(record);\n assert.deepEqual(record, expectedResult);\n}\n"],
5
- "mappings": "AAAA,OAAO,YAAY;AACnB,SAAQ,kBAAiB;AACzB,OAAO,sBAAsB;AAC7B,SAAQ,eAAc;AACtB,OAAO,mBAAmB;AAC1B,OAAO,uBAAuB;AAE9B,cAAc;AAAA,EACZ;AAAA,EACA,MAAM,CAAC,YAAY,SAAS,MAAM,iBAAiB,iBAAiB;AAAA,EACpE,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,QAAQ,QAAQ;AAAA,EAClB;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,YAAY;AAClB,2BAAqB;AAAA,IACvB;AAAA,EACF;AACF,CAAC;AAED,MAAM,QAAQ,kBAAkB,+DAA+D;AAE/F,eAAe,uBAAuB;AACpC,QAAM,YAAY,MAAM,iBAAiB;AAEzC,SAAO,MAAM,OAAO,WAAW,QAAQ;AACvC,SAAO,MAAM,OAAO,UAAU,aAAa,QAAQ;AACnD,SAAO,MAAM,OAAO,UAAU,UAAU,UAAU;AACpD;AAEA,eAAe,SAAS,EAAC,YAAY,UAAU,MAAM,MAAM,MAAK,GAAG;AACjE,MAAI,YAAY,OAAO;AACrB,UAAM,eAAe;AACrB;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,iBAAiB;AACzC,QAAM,SAAS,IAAI,WAAW,WAAW,aAAa,CAAC;AACvD,QAAM,iBAAiB,WAAW,qBAAqB;AAGvD,MAAI,CAAC,KAAK;AACR,UAAM,SAAS,MAAM,UAAU,SAAS,MAAM;AAC9C,WAAO,UAAU,QAAQ,cAAc;AACvC;AAAA,EACF;AAEA,QAAM,UAAU,IAAI,MAAM;AAC1B,SAAO,UAAU,QAAQ,cAAc;AACzC;",
4
+ "sourcesContent": ["import assert from 'node:assert';\nimport createDebugLogger from 'debug';\nimport fetchMock from 'fetch-mock';\n\nimport validatorFactory from './translate-terms.js';\n\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\nimport {fakeData} from '../test-fixtures/translate-terms-data.js';\n\nconst uris = [\n 'http://www.yso.fi/onto/yso/p13299',\n 'http://www.yso.fi/onto/yso/p111739',\n 'http://www.yso.fi/onto/yso/p6197061979',\n 'http://www.yso.fi/onto/yso/p6196061969',\n 'http://urn.fi/URN:NBN:fi:au:slm:s161'\n];\n\n\n\ngenerateTests({\n callback,\n path: [import.meta.dirname, '..', 'test-fixtures', 'translate-terms'],\n useMetadataFile: true,\n recurse: false,\n fixura: {\n reader: READERS.JSON\n },\n hooks: {\n before: async () => {\n\n fetchMock.mockGlobal()\n .get(`https://api.finto.fi/rest/v1/data?uri=${uris[0]}&format=application%2Fjson`, {status: 200, headers: {}, body: fakeData})\n .get(`https://api.finto.fi/rest/v1/data?uri=${uris[1]}&format=application%2Fjson`, {status: 200, headers: {}, body: fakeData})\n .get(`https://api.finto.fi/rest/v1/data?uri=${uris[2]}&format=application%2Fjson`, {status: 200, headers: {}, body: fakeData})\n .get(`https://api.finto.fi/rest/v1/data?uri=${uris[3]}&format=application%2Fjson`, {status: 200, headers: {}, body: fakeData})\n .get(`https://api.finto.fi/rest/v1/data?uri=${uris[4]}&format=application%2Fjson`, {status: 200, headers: {}, body: fakeData});\n\n\n testValidatorFactory();\n }\n }\n});\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/translate-terms:test');\n\nasync function testValidatorFactory() {\n const validator = await validatorFactory();\n\n assert.equal(typeof validator, 'object');\n assert.equal(typeof validator.description, 'string');\n assert.equal(typeof validator.validate, 'function');\n}\n\nasync function callback({getFixture, enabled = true, fix = false}) {\n if (enabled === false) {\n debug('TEST SKIPPED!');\n return;\n }\n\n const validator = await validatorFactory();\n const record = new MarcRecord(getFixture('record.json'));\n const expectedResult = getFixture('expectedResult.json');\n // console.log(expectedResult); // eslint-disable-line\n\n if (!fix) {\n const result = await validator.validate(record);\n assert.deepEqual(result, expectedResult);\n return;\n }\n\n await validator.fix(record);\n assert.deepEqual(record, expectedResult);\n}\n"],
5
+ "mappings": "AAAA,OAAO,YAAY;AACnB,OAAO,uBAAuB;AAC9B,OAAO,eAAe;AAEtB,OAAO,sBAAsB;AAE7B,SAAQ,kBAAiB;AACzB,SAAQ,eAAc;AACtB,OAAO,mBAAmB;AAC1B,SAAQ,gBAAe;AAEvB,MAAM,OAAO;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIA,cAAc;AAAA,EACZ;AAAA,EACA,MAAM,CAAC,YAAY,SAAS,MAAM,iBAAiB,iBAAiB;AAAA,EACpE,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,QAAQ,QAAQ;AAAA,EAClB;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,YAAY;AAElB,gBAAU,WAAW,EACpB,IAAI,yCAAyC,KAAK,CAAC,CAAC,8BAA8B,EAAC,QAAQ,KAAK,SAAS,CAAC,GAAG,MAAM,SAAQ,CAAC,EAC5H,IAAI,yCAAyC,KAAK,CAAC,CAAC,8BAA8B,EAAC,QAAQ,KAAK,SAAS,CAAC,GAAG,MAAM,SAAQ,CAAC,EAC5H,IAAI,yCAAyC,KAAK,CAAC,CAAC,8BAA8B,EAAC,QAAQ,KAAK,SAAS,CAAC,GAAG,MAAM,SAAQ,CAAC,EAC5H,IAAI,yCAAyC,KAAK,CAAC,CAAC,8BAA8B,EAAC,QAAQ,KAAK,SAAS,CAAC,GAAG,MAAM,SAAQ,CAAC,EAC5H,IAAI,yCAAyC,KAAK,CAAC,CAAC,8BAA8B,EAAC,QAAQ,KAAK,SAAS,CAAC,GAAG,MAAM,SAAQ,CAAC;AAG7H,2BAAqB;AAAA,IACvB;AAAA,EACF;AACF,CAAC;AAED,MAAM,QAAQ,kBAAkB,+DAA+D;AAE/F,eAAe,uBAAuB;AACpC,QAAM,YAAY,MAAM,iBAAiB;AAEzC,SAAO,MAAM,OAAO,WAAW,QAAQ;AACvC,SAAO,MAAM,OAAO,UAAU,aAAa,QAAQ;AACnD,SAAO,MAAM,OAAO,UAAU,UAAU,UAAU;AACpD;AAEA,eAAe,SAAS,EAAC,YAAY,UAAU,MAAM,MAAM,MAAK,GAAG;AACjE,MAAI,YAAY,OAAO;AACrB,UAAM,eAAe;AACrB;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,iBAAiB;AACzC,QAAM,SAAS,IAAI,WAAW,WAAW,aAAa,CAAC;AACvD,QAAM,iBAAiB,WAAW,qBAAqB;AAGvD,MAAI,CAAC,KAAK;AACR,UAAM,SAAS,MAAM,UAAU,SAAS,MAAM;AAC9C,WAAO,UAAU,QAAQ,cAAc;AACvC;AAAA,EACF;AAEA,QAAM,UAAU,IAAI,MAAM;AAC1B,SAAO,UAAU,QAAQ,cAAc;AACzC;",
6
6
  "names": []
7
7
  }
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 {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\n\n\nexport function subfieldArraysContainSameData(arr1, arr2) {\n if ( !arr1.every(sf => arr2.some(sf2 => subfieldsAreIdentical(sf, sf2))) ) {\n return false;\n }\n\n return arr2.every(sf2 => arr1.some(sf => subfieldsAreIdentical(sf, sf2)));\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 // NB! Only $w, $0, $1, $5, $6 and $8 are really control subfields. In Finland $9 is oft a control subfield\n // $3 material (part of the whole thing)\n // $4 means 'relationship' (similar to relator terms at least in X00 and similar)\n // $7 is usually provinance subfield. However, it can be stored in other subfields as well. See merge-fields/dataProvenance.js for details\n // However, change this only if needed. Maybe all provinance subfields should return true?\n // This may become relevant when AI starts to create stuff...\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\n\n\nexport function subfieldArraysContainSameData(arr1, arr2) {\n if ( !arr1.every(sf => arr2.some(sf2 => subfieldsAreIdentical(sf, sf2))) ) {\n return false;\n }\n\n return arr2.every(sf2 => arr1.some(sf => subfieldsAreIdentical(sf, sf2)));\n}"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "url": "https://github.com/NatLibFi/marc-record-validators-melinda"
15
15
  },
16
16
  "license": "MIT",
17
- "version": "12.0.0-alpha.6",
17
+ "version": "12.0.0-alpha.8",
18
18
  "main": "./dist/index.js",
19
19
  "publishConfig": {
20
20
  "access": "public"
@@ -33,19 +33,20 @@
33
33
  "dev:debug": "cross-env LOG_LEVEL=debug DEBUG=@natlibfi/* NODE_ENV=test"
34
34
  },
35
35
  "dependencies": {
36
+ "@natlibfi/iso9-1995": "next",
36
37
  "@natlibfi/issn-verify": "^1.0.6",
37
38
  "@natlibfi/marc-record": "next",
38
39
  "@natlibfi/marc-record-serializers": "next",
39
40
  "@natlibfi/marc-record-validate": "next",
40
41
  "@natlibfi/melinda-commons": "next",
41
42
  "@natlibfi/sfs-4900": "next",
42
- "@natlibfi/iso9-1995": "next",
43
43
  "@natlibfi/sru-client": "next",
44
44
  "cld3-asm": "^4.0.0",
45
45
  "clone": "^2.1.2",
46
46
  "debug": "^4.4.3",
47
- "isbn3": "^1.2.15",
47
+ "isbn3": "1.2.15",
48
48
  "langs": "^2.0.0",
49
+ "undici": "^7.16.0",
49
50
  "xml2js": "^0.6.2",
50
51
  "xregexp": "^5.1.2"
51
52
  },
@@ -56,12 +57,12 @@
56
57
  "@natlibfi/fixugen": "next",
57
58
  "@natlibfi/fixura": "next",
58
59
  "cross-env": "^10.0.0",
59
- "esbuild": "^0.25.10",
60
- "eslint": "^9.36.0",
61
- "fetch-mock": "^12.5.4"
60
+ "esbuild": "^0.25.12",
61
+ "eslint": "^9.39.1",
62
+ "fetch-mock": "^12.6.0"
62
63
  },
63
64
  "overrides": {
64
65
  "nanoid": "^3.3.8"
65
66
  },
66
- "nvolkComment": "cld3-asm 4.0.0 uses emscripten-wasm-loader ^3.0.3 which uses problematic, non-secure nanoid version 2.X.X"
67
+ "nvolkComment": "cld3-asm 4.0.0 uses emscripten-wasm-loader ^3.0.3 which uses problematic, non-secure nanoid version 2.X.X. Isbn3 has breaking changes in 1.2.16-18 at least."
67
68
  }