@natlibfi/marc-record-validators-melinda 13.0.4 → 13.0.5

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.
Files changed (31) hide show
  1. package/dist/cyrillux-usemarcon-replacement.test.js +2 -2
  2. package/dist/cyrillux-usemarcon-replacement.test.js.map +2 -2
  3. package/dist/merge-fields/mergeConstraints.js +1 -1
  4. package/dist/merge-fields/mergeConstraints.js.map +2 -2
  5. package/dist/merge-fields/mergeField.js +2 -2
  6. package/dist/merge-fields/mergeField.js.map +2 -2
  7. package/dist/merge-fields/mergeOrAddSubfield.js +19 -5
  8. package/dist/merge-fields/mergeOrAddSubfield.js.map +2 -2
  9. package/dist/punctuation2.js +16 -8
  10. package/dist/punctuation2.js.map +2 -2
  11. package/dist/punctuation2.test.js +2 -2
  12. package/dist/punctuation2.test.js.map +2 -2
  13. package/dist/sortSubfields.js +2 -2
  14. package/dist/sortSubfields.js.map +2 -2
  15. package/package.json +8 -8
  16. package/src/cyrillux-usemarcon-replacement.test.js +2 -2
  17. package/src/merge-fields/mergeConstraints.js +1 -1
  18. package/src/merge-fields/mergeField.js +2 -2
  19. package/src/merge-fields/mergeOrAddSubfield.js +28 -5
  20. package/src/punctuation2.js +20 -12
  21. package/src/punctuation2.test.js +2 -2
  22. package/src/sortSubfields.js +1 -1
  23. package/test-fixtures/cyrillux-usemarcon-replacement/f10/metadata.json +1 -1
  24. package/test-fixtures/merge-fields/f04/expectedResult.json +1 -2
  25. package/test-fixtures/merge-fields/f04/record.json +1 -2
  26. package/test-fixtures/merge-fields/f700_01/expectedResult.json +18 -0
  27. package/test-fixtures/merge-fields/f700_01/metadata.json +5 -0
  28. package/test-fixtures/merge-fields/f700_01/record.json +24 -0
  29. package/test-fixtures/merge-fields/f830_01/expectedResult.json +20 -0
  30. package/test-fixtures/merge-fields/f830_01/metadata.json +6 -0
  31. package/test-fixtures/merge-fields/f830_01/record.json +20 -0
@@ -60,7 +60,8 @@ function isIrrelevantSubfield(subfield, tag) {
60
60
  if (subfield.code === dataProvenanceSubfieldCode) {
61
61
  return true;
62
62
  }
63
- return !isContentSubfieldCode(subfield.code); // Currently this contains other stuff as well ($3, $4, $7, $9...)
63
+ // control subfields, data provenance subfields etc do not affect the punctuation of the previous field
64
+ return !isContentSubfieldCode(subfield.code);
64
65
  }
65
66
 
66
67
 
@@ -129,7 +130,7 @@ const cleanPuncBeforeLanguage = {'code': 'atvxyz', 'followedBy': 'l', 'context':
129
130
  const addX00aComma = {'add': ',', 'code': 'abcqejt', 'followedBy': 'cdegnr', 'context': doesNotEndInPunc, 'contextRHS': allowsPuncRHS};
130
131
  const addX00dComma = {'name': 'X00$d ending in "-" does not get comma', 'add': ',', 'code': 'd', 'followedBy': 'cdeg', 'context': /[^-,.!]$/u, 'contextRHS': allowsPuncRHS};
131
132
  const addX00aComma2 = {'add': ',', 'code': 'abcdej', 'followedBy': 'cdeg', 'context': /(?:[A-Z]|Å|Ä|Ö)\.$/u, 'contextRHS': allowsPuncRHS};
132
- const addX00Dot = {'add': '.', 'code': 'abcdetv', 'followedBy': 'fklptu', 'context': needsPuncAfterAlphanumeric};
133
+ const addX00Dot = {'name': 'addX00Dot', 'add': '.', 'code': 'abcdetv', 'followedBy': 'fklptu', 'context': needsPuncAfterAlphanumeric};
133
134
  const addEntryFieldFinalDot = {'name': 'X00 final dot', 'add': '.', 'code': 'abcdefghijklmnopqrstuvwxyz', 'followedBy': '#', 'context': /[^.)!?-]$/u};
134
135
 
135
136
 
@@ -144,7 +145,7 @@ const addX11Spacecolon = {name: '611 space colon(y :-)', add: ' :', code: 'nd',
144
145
  const addDotBeforeLanguageSubfieldL = {'name': 'Add dot before $l', 'add': '.', 'code': 'abepst', 'followedBy': 'l', 'context': doesNotEndInPunc};
145
146
 
146
147
  // 490:
147
- const addSemicolonBeforeVolumeDesignation = {'name': 'Add " ;" before $v', 'add': ' ;', 'code': 'atxyz', 'followedBy': 'v', 'context': /[^;]$/u};
148
+ const addSemicolonBeforeVolumeDesignation = {'name': 'Add " ;" before $v', 'add': ' ;', 'followedBy': 'v', 'context': /[^;]$/u};
148
149
 
149
150
  const NONE = 0;
150
151
  const ADD = 2;
@@ -245,7 +246,9 @@ const legalX10punc = [cleanLegalX10Comma, cleanLegalX10Dot, cleanX00eDot, ...leg
245
246
 
246
247
  const cleanLegalSeriesTitle = [ // 490 and 830
247
248
  {'code': 'a', 'followedBy': 'a', 'remove': / =$/u},
248
- {'code': 'axyz', 'followedBy': 'xyz', 'remove': /,$/u, 'context': /.,$/u},
249
+ {'code': 'a', 'followedBy': 'n', 'remove': /\.$/u}, // f830-only
250
+ {'code': 'n', 'followedBy': 'p', 'remove': /,$/u}, // f830-only
251
+ {'code': 'anpxyz', 'followedBy': 'xyz', 'remove': /,$/u, 'context': /.,$/u},
249
252
  {'code': 'axyz', 'followedBy': 'v', 'remove': / *;$/u}
250
253
  ];
251
254
 
@@ -299,7 +302,7 @@ const cleanValidPunctuationRules = {
299
302
  '611': legalX11Punc,
300
303
  '630': legalEntryField,
301
304
  // Experimental, MET366-ish (end punc in internationally valid, but we don't use it here in Finland):
302
- '648': [{'code': 'a', 'content': /^[0-9]+\.$/u, 'ind2': ['4'], 'remove': /\.$/u}],
305
+ '648': [{'code': 'a', 'context': /^[0-9]+\.$/u, 'ind2': ['4'], 'remove': /\.$/u}],
303
306
  '700': legalX00punc,
304
307
  '710': legalX10punc,
305
308
  '711': legalX11Punc,
@@ -313,13 +316,18 @@ const cleanValidPunctuationRules = {
313
316
 
314
317
 
315
318
  // Overgeneralizes a bit: eg. addColonToRelationshipInformation only applies to 700/710 but as others don't have $i, it's fine.
319
+ // Also addSemicolonBeforeVolumeDesignation applies only to 8XX:
316
320
  const addToAllEntryFields = [addDotBeforeLanguageSubfieldL, addSemicolonBeforeVolumeDesignation, addColonToRelationshipInformation, addEntryFieldFinalDot];
317
321
 
318
322
 
319
323
  const addX00 = [addXX0iColon, addX00aComma, addX00aComma2, addX00Dot, addX00dComma, ...addToAllEntryFields];
320
324
  const addX10 = [addXX0iColon, addX10bDot, addX10Comma, addX10Dot, ...addToAllEntryFields];
321
325
  const addX11 = [...addToAllEntryFields, addX11Spacecolon];
322
- const addX30 = [...addToAllEntryFields];
326
+ const addX30 = [
327
+ ...addToAllEntryFields,
328
+ {'name': 'X30$a dot', 'code': 'a', 'followedBy': 'knp', 'add': '.', 'context': needsPuncAfterAlphanumeric},
329
+ {'name': 'X30 final dot', 'code': 'adfghklmnoprstv', 'followedBy': '#', 'add': '.', 'context': needsPuncAfterAlphanumeric}
330
+ ];
323
331
 
324
332
  const add24X = [
325
333
  {'code': 'i', 'followedBy': 'a', 'add': ':', 'context': needsPuncAfterAlphanumeric},
@@ -339,7 +347,7 @@ const add245 = [
339
347
 
340
348
  const addSeriesTitle = [ // 490 and 830
341
349
  {'code': 'a', 'followedBy': 'a', 'add': ' =', 'context': defaultNeedsPuncAfter2},
342
- {'code': 'axyz', 'followedBy': 'xy', 'add': ',', 'context': defaultNeedsPuncAfter2},
350
+ {'code': 'anpxyz', 'followedBy': 'pxy', 'add': ',', 'context': defaultNeedsPuncAfter2},
343
351
  addSemicolonBeforeVolumeDesignation // eg. 490$axyz-$v
344
352
  ];
345
353
 
@@ -521,7 +529,7 @@ function applyPunctuationRules(field, subfield1, subfield2, ruleArray = null, op
521
529
 
522
530
  //nvdebug(`OP=${operation} ${tag2}: '${subfield1.code}: ${subfield1.value}' ??? '${subfield2 ? subfield2.code : '#'}'`, debugDev);
523
531
  const candRules = ruleArray[tag2];
524
- candRules.every(rule => { // uses "every", not "forEach", so that only one rule is applies to the given subfields
532
+ candRules.every(rule => { // uses "every", not "forEach", so that only one rule is applied to the given subfields
525
533
  //debugRule(rule);
526
534
  if (!checkRule(rule, field, subfield1, subfield2)) {
527
535
  return true;
@@ -578,21 +586,21 @@ export function fieldStripPunctuation(field) {
578
586
  return field;
579
587
  }
580
588
 
581
- export function fieldFixPunctuation(field) {
589
+ export function fieldFixPunctuation(field, externalEndPunctuation = false) {
582
590
  if (!field.subfields) {
583
591
  return field;
584
592
  }
585
593
  //nvdebug(`################### fieldFixPunctuation() TEST ${fieldToString(field)}`, debugDev);
586
594
 
587
595
  field.subfields.forEach((sf, i) => {
588
- // NB! instead of next subfield, we should actually get next *non-control-subfield*!!!
589
- // (In plain English: We should skip $0 - $9 at least, maybe $w as well...)
596
+ // NB! instead of next subfield, we get next *non-control-subfield*!!!
597
+ // (In plain English: We skip $0 ... $9 at least, maybe $w as well...)
590
598
  // We'll need some magic for field 257 here, do we? (Also Finnish lexicons vs global lexicons in 65X fields)
591
599
  subfieldFixPunctuation(field, sf, getNextRelevantSubfield(field, i));
592
600
  });
593
601
 
594
602
  // Use shared code for final punctuation (sadly this does not fix intermediate punc):
595
- if (field.useExternalEndPunctuation) {
603
+ if (externalEndPunctuation || field.useExternalEndPunctuation) {
596
604
  // addFinalPunctuation(field); // local version. use shared code instead.
597
605
  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)
598
606
  }
@@ -1,4 +1,4 @@
1
- import assert from 'node:assert';
1
+ import assert from 'node:assert/strict';
2
2
  import {MarcRecord} from '@natlibfi/marc-record';
3
3
  import validatorFactory from './punctuation2.js';
4
4
  import {READERS} from '@natlibfi/fixura';
@@ -42,5 +42,5 @@ async function callback({getFixture, fix = false}) {
42
42
  }
43
43
 
44
44
  await validator.fix(record);
45
- assert.deepEqual(record, expectedResult);
45
+ assert.deepEqual(record, new MarcRecord(expectedResult));
46
46
  }
@@ -126,7 +126,7 @@ const subfieldSortOrder = [
126
126
  {'tag': '800', 'sortOrder': sortOrderForX00},
127
127
  {'tag': '810', 'sortOrder': sortOrderForX10},
128
128
  {'tag': '811', 'sortOrder': sortOrderForX11},
129
- {'tag': '830', 'sortOrder': ['a', 'n', 'x', 'v']}, // INCOMPLETE, SAME AS 490? APPARENTLY NOT...
129
+ {'tag': '830', 'sortOrder': ['a', 'n', 'p', 'x', 'v']}, // Sort of an extension of f490...
130
130
  {'tag': '856', 'sortOrder': ['3', 'u', 'q', 'x', 'y', 'z', '5']}, // incomplete, LoC examples are inconclusive
131
131
  {'tag': '880', 'sortOrder': ['a']},
132
132
  {'tag': '946', 'sortOrder': sortOrderFor246},
@@ -1,5 +1,5 @@
1
1
  {
2
- "description": "Fix Cyrillux-related stuff: split 410 to 490 and 810, and split 440 to 490 and 810",
2
+ "description": "Fix Cyrillux-related stuff: split 410 to 490 and 810, and split 440 to 490 and 830",
3
3
  "comment": "Also note few indicator changes",
4
4
  "only": false,
5
5
  "fix": true
@@ -7,8 +7,7 @@
7
7
  { "code": "d", "value": "1890-1940," },
8
8
  { "code": "e", "value": "säveltäjä," },
9
9
  { "code": "e", "value": "sanoittaja," },
10
- { "code": "e", "value": "sovittaja." },
11
- { "code": "0", "value": "(FI-ASTERI-N)000123456" }
10
+ { "code": "e", "value": "sovittaja." }
12
11
  ]}
13
12
  ]
14
13
  }
@@ -7,8 +7,7 @@
7
7
  ]},
8
8
  { "tag": "100", "ind1": "1", "ind2": " ", "subfields": [
9
9
  { "code": "a", "value": "Sukunimi, Etunimi," },
10
- { "code": "e", "value": "sovittaja." },
11
- { "code": "0", "value": "(FI-ASTERI-N)000123456" }
10
+ { "code": "e", "value": "sovittaja." }
12
11
  ]},
13
12
  { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
14
13
  { "code": "a", "value": "Sukunimi, Etunimi," },
@@ -0,0 +1,18 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "leader": "12345cam a22123454i 4500",
4
+ "fields": [
5
+ { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
6
+ { "code": "a", "value": "Sukunimi, A." },
7
+ { "code": "0", "value": "(FI-ASTERI-N)000000111" }
8
+ ]},
9
+ { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
10
+ { "code": "a", "value": "Sukunimi, B." },
11
+ { "code": "q", "value": "(Börje)," },
12
+ { "code": "d", "value": "1234-1299." },
13
+ { "code": "0", "value": "(FI-ASTERI-N)000000123" }
14
+ ]}
15
+
16
+
17
+ ]
18
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "description": "F700/01: don't merge years from a non-authorized pair, but merge them from authorized",
3
+ "only": true,
4
+ "fix": true
5
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "leader": "12345cam a22123454i 4500",
3
+ "fields": [
4
+ { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
5
+ { "code": "a", "value": "Sukunimi, A." },
6
+ { "code": "0", "value": "(FI-ASTERI-N)000000111" }
7
+ ]},
8
+ { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
9
+ { "code": "a", "value": "Sukunimi, A.," },
10
+ { "code": "d", "value": "1234-1299." }
11
+ ]},
12
+ { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
13
+ { "code": "a", "value": "Sukunimi, B." },
14
+ { "code": "q", "value": "(Börje)" },
15
+ { "code": "0", "value": "(FI-ASTERI-N)000000123" }
16
+ ]},
17
+ { "tag": "700", "ind1": "1", "ind2": " ", "subfields": [
18
+ { "code": "a", "value": "Sukunimi, B.," },
19
+ { "code": "d", "value": "1234-1299." },
20
+ { "code": "0", "value": "(FI-ASTERI-N)000000123" }
21
+ ]}
22
+
23
+ ]
24
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "fields": [
4
+ { "tag": "830", "ind1": " ", "ind2": "0", "subfields": [
5
+ { "code": "a", "value": "Annales." },
6
+ { "code": "n", "value": "Series B," },
7
+ { "code": "p", "value": "Humaniora ;" },
8
+ { "code": "v", "value": "153, 4" }
9
+ ] },
10
+ { "tag": "830", "ind1": " ", "ind2": "0", "subfields": [
11
+ { "code": "a", "value": "Annales." },
12
+ { "code": "n", "value": "Series B," },
13
+ { "code": "x", "value": "0066-2011 ;" },
14
+ { "code": "v", "value": "153, 4" },
15
+ { "code": "0", "value": "(FI-ASTERI-W)000015651" }
16
+ ] }
17
+ ],
18
+ "leader": "01331cam a22003498i 4500"
19
+
20
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "description": "f830/01: fields should not merge, as $0 vs $p blocks pairing",
3
+ "fix": true,
4
+ "only": false,
5
+ "tagPattern": "^830$"
6
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "fields": [
4
+ { "tag": "830", "ind1": " ", "ind2": "0", "subfields": [
5
+ { "code": "a", "value": "Annales." },
6
+ { "code": "n", "value": "Series B," },
7
+ { "code": "p", "value": "Humaniora ;" },
8
+ { "code": "v", "value": "153, 4" }
9
+ ] },
10
+ { "tag": "830", "ind1": " ", "ind2": "0", "subfields": [
11
+ { "code": "a", "value": "Annales." },
12
+ { "code": "n", "value": "Series B," },
13
+ { "code": "x", "value": "0066-2011 ;" },
14
+ { "code": "v", "value": "153, 4" },
15
+ { "code": "0", "value": "(FI-ASTERI-W)000015651" }
16
+ ] }
17
+ ],
18
+ "leader": "01331cam a22003498i 4500"
19
+
20
+ }