@natlibfi/marc-record-validators-melinda 10.13.0 → 10.13.1-alpha.2

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 (72) hide show
  1. package/.github/workflows/melinda-node-tests.yml +3 -3
  2. package/dist/field-505-separators.js +77 -0
  3. package/dist/field-505-separators.js.map +1 -0
  4. package/dist/field-505-separators.spec.js +51 -0
  5. package/dist/field-505-separators.spec.js.map +1 -0
  6. package/dist/fixRelatorTerms.js +278 -0
  7. package/dist/fixRelatorTerms.js.map +1 -0
  8. package/dist/fixRelatorTerms.spec.js +51 -0
  9. package/dist/fixRelatorTerms.spec.js.map +1 -0
  10. package/dist/index.js +101 -3
  11. package/dist/index.js.map +1 -1
  12. package/dist/normalize-qualifying-information.js +97 -0
  13. package/dist/normalize-qualifying-information.js.map +1 -0
  14. package/dist/normalize-qualifying-information.spec.js +51 -0
  15. package/dist/normalize-qualifying-information.spec.js.map +1 -0
  16. package/dist/normalizeSubfieldValueForComparison.js +12 -3
  17. package/dist/normalizeSubfieldValueForComparison.js.map +1 -1
  18. package/dist/prepublicationUtils.js +8 -26
  19. package/dist/prepublicationUtils.js.map +1 -1
  20. package/dist/punctuation2.js +7 -2
  21. package/dist/punctuation2.js.map +1 -1
  22. package/dist/removeInferiorDataFields.js +69 -10
  23. package/dist/removeInferiorDataFields.js.map +1 -1
  24. package/dist/utils.js +12 -0
  25. package/dist/utils.js.map +1 -1
  26. package/package.json +11 -11
  27. package/src/field-505-separators.js +75 -0
  28. package/src/field-505-separators.spec.js +52 -0
  29. package/src/fixRelatorTerms.js +233 -0
  30. package/src/fixRelatorTerms.spec.js +52 -0
  31. package/src/index.js +33 -4
  32. package/src/normalize-qualifying-information.js +92 -0
  33. package/src/normalize-qualifying-information.spec.js +52 -0
  34. package/src/normalizeSubfieldValueForComparison.js +14 -3
  35. package/src/prepublicationUtils.js +8 -25
  36. package/src/punctuation2.js +3 -2
  37. package/src/removeInferiorDataFields.js +70 -10
  38. package/src/utils.js +12 -0
  39. package/test-fixtures/field-505-separators/01/expectedResult.json +7 -0
  40. package/test-fixtures/field-505-separators/01/metadata.json +7 -0
  41. package/test-fixtures/field-505-separators/01/record.json +25 -0
  42. package/test-fixtures/field-505-separators/02/expectedResult.json +27 -0
  43. package/test-fixtures/field-505-separators/02/metadata.json +7 -0
  44. package/test-fixtures/field-505-separators/02/record.json +25 -0
  45. package/test-fixtures/fix-relator-terms/f01/expectedResult.json +14 -0
  46. package/test-fixtures/fix-relator-terms/f01/metadata.json +6 -0
  47. package/test-fixtures/fix-relator-terms/f01/record.json +13 -0
  48. package/test-fixtures/fix-relator-terms/f01b/expectedResult.json +12 -0
  49. package/test-fixtures/fix-relator-terms/f01b/metadata.json +6 -0
  50. package/test-fixtures/fix-relator-terms/f01b/record.json +11 -0
  51. package/test-fixtures/fix-relator-terms/f02/expectedResult.json +12 -0
  52. package/test-fixtures/fix-relator-terms/f02/metadata.json +6 -0
  53. package/test-fixtures/fix-relator-terms/f02/record.json +11 -0
  54. package/test-fixtures/normalize-qualifying-information/01/expectedResult.json +8 -0
  55. package/test-fixtures/normalize-qualifying-information/01/metadata.json +7 -0
  56. package/test-fixtures/normalize-qualifying-information/01/record.json +25 -0
  57. package/test-fixtures/normalize-qualifying-information/02/expectedResult.json +27 -0
  58. package/test-fixtures/normalize-qualifying-information/02/metadata.json +7 -0
  59. package/test-fixtures/normalize-qualifying-information/02/record.json +25 -0
  60. package/test-fixtures/punctuation2/97/expectedResult.json +6 -1
  61. package/test-fixtures/punctuation2/97/record.json +5 -0
  62. package/test-fixtures/remove-inferior-datafields/f09/expectedResult.json +20 -0
  63. package/test-fixtures/remove-inferior-datafields/f09/metadata.json +6 -0
  64. package/test-fixtures/remove-inferior-datafields/f09/record.json +30 -0
  65. package/test-fixtures/remove-inferior-datafields/f10/expectedResult.json +17 -0
  66. package/test-fixtures/remove-inferior-datafields/f10/metadata.json +6 -0
  67. package/test-fixtures/remove-inferior-datafields/f10/record.json +27 -0
  68. package/test-fixtures/remove-inferior-datafields/f11/expectedResult.json +14 -0
  69. package/test-fixtures/remove-inferior-datafields/f11/metadata.json +6 -0
  70. package/test-fixtures/remove-inferior-datafields/f11/record.json +18 -0
  71. package/test-fixtures/strip-punctuation/98/expectedResult.json +5 -0
  72. package/test-fixtures/strip-punctuation/98/record.json +5 -0
@@ -0,0 +1,52 @@
1
+ import {expect} from 'chai';
2
+ import {MarcRecord} from '@natlibfi/marc-record';
3
+ import validatorFactory from './normalize-qualifying-information';
4
+ import {READERS} from '@natlibfi/fixura';
5
+ import generateTests from '@natlibfi/fixugen';
6
+ import createDebugLogger from 'debug';
7
+
8
+ generateTests({
9
+ callback,
10
+ path: [__dirname, '..', 'test-fixtures', 'normalize-qualifying-information'],
11
+ useMetadataFile: true,
12
+ recurse: false,
13
+ fixura: {
14
+ reader: READERS.JSON
15
+ },
16
+ mocha: {
17
+ before: () => testValidatorFactory()
18
+ }
19
+ });
20
+ const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/normalize-qualifying-information:test');
21
+
22
+ async function testValidatorFactory() {
23
+ const validator = await validatorFactory();
24
+
25
+ expect(validator)
26
+ .to.be.an('object')
27
+ .that.has.any.keys('description', 'validate');
28
+
29
+ expect(validator.description).to.be.a('string');
30
+ expect(validator.validate).to.be.a('function');
31
+ }
32
+
33
+ async function callback({getFixture, enabled = true, fix = false}) {
34
+ if (enabled === false) {
35
+ debug('TEST SKIPPED!');
36
+ return;
37
+ }
38
+
39
+ const validator = await validatorFactory();
40
+ const record = new MarcRecord(getFixture('record.json'));
41
+ const expectedResult = getFixture('expectedResult.json');
42
+ // console.log(expectedResult); // eslint-disable-line
43
+
44
+ if (!fix) {
45
+ const result = await validator.validate(record);
46
+ expect(result).to.eql(expectedResult);
47
+ return;
48
+ }
49
+
50
+ await validator.fix(record);
51
+ expect(record).to.eql(expectedResult);
52
+ }
@@ -8,6 +8,7 @@ const debug = createDebugLogger('@natlibfi/melinda-marc-record-merge-reducers:no
8
8
  const debugDev = debug.extend('dev');
9
9
 
10
10
  export function subfieldContainsPartData(tag, subfieldCode) {
11
+ // NB! Used by reducers' mergeSubield.js
11
12
  if (subfieldCode === 'v' && ['490', '800', '810', '811', '830'].includes(tag)) {
12
13
  return true;
13
14
  }
@@ -18,8 +19,9 @@ export function subfieldContainsPartData(tag, subfieldCode) {
18
19
  }
19
20
 
20
21
  function splitPartData(originalValue) {
22
+ // Remove brackets from number-only:
21
23
  const value = originalValue.replace(/^\[([0-9]+)\][-.,:; ]*$/ui, '$1'); // eslint-disable-line prefer-named-capture-group
22
- const splitPoint = value.lastIndexOf(' ');
24
+ const splitPoint = value.lastIndexOf(' '); // MRA-627: "5, 2017" should be split here. Think of this later on...
23
25
  if (splitPoint === -1) {
24
26
  return [undefined, value];
25
27
  }
@@ -33,13 +35,19 @@ function normalizePartType(originalValue) {
33
35
  return undefined;
34
36
  }
35
37
  const value = originalValue.toLowerCase();
36
- // Return Finnish singular nominative. Best-ish for debug purposes...
37
- if (['osa', 'part', 'teil'].includes(value)) {
38
+
39
+ // Return Finnish singular nominative. Choise of language is arbitrary. This is best-ish for debug purposes...
40
+ if (['n:o', 'no', 'nr', 'nro', 'number', 'numero', 'nummer'].includes(value)) {
41
+ return 'numero';
42
+ }
43
+ if (['band', 'bd', 'häfte', 'nide', 'osa', 'part', 'teil', 'vol', 'vol.', 'volume'].includes(value)) {
38
44
  return 'osa';
39
45
  }
46
+
40
47
  if (['p.', 'page', 'pages', 'pp.', 's.', 'sidor', 'sivu', 'sivut'].includes(value)) {
41
48
  return 'sivu';
42
49
  }
50
+
43
51
  return value;
44
52
  }
45
53
 
@@ -67,12 +75,15 @@ function splitAndNormalizePartData(value) {
67
75
  }
68
76
 
69
77
  export function partsAgree(value1, value2, tag, subfieldCode) {
78
+ // Note, that parts can not be normalized away, as "2" can agree with "Part 2" and "Raita 2" and "Volume 2"...
79
+ // NB! Used by reducers' mergeSubield.js
70
80
  if (!subfieldContainsPartData(tag, subfieldCode)) {
71
81
  return false;
72
82
  }
73
83
  const [partType1, partNumber1] = splitAndNormalizePartData(value1);
74
84
  const [partType2, partNumber2] = splitAndNormalizePartData(value2);
75
85
  if (partNumber1 !== partNumber2) {
86
+ // MRA-627: This should/could accept 5/1997
76
87
  return false;
77
88
  }
78
89
  if (partType1 === undefined || partType2 === undefined || partType1 === partType2) {
@@ -41,8 +41,12 @@ export function fieldRefersToTarkistettuEnnakkotieto(field) {
41
41
 
42
42
 
43
43
  export function fieldRefersToEnnakkotieto(field) {
44
- // NB! This matches also 'TARKISTETTU ENNAKKOTIETO' case!
45
- return containsSubstringInSubfieldA(field, 'ENNAKKOTIETO');
44
+ // NB! This no longer matches 'TARKISTETTU ENNAKKOTIETO' case! Bug or Feature?
45
+ if (containsSubstringInSubfieldA(field, 'ENNAKKOTIETO') && !fieldRefersToTarkistettuEnnakkotieto(field)) {
46
+ return true;
47
+ }
48
+ // MRA-420: "EI VIELÄ ILMESTYNYT" is a Helmet note, that is semantically similar to ENNAKKOTIETO:
49
+ return containsSubstringInSubfieldA(field, 'EI VIELÄ ILMESTYNYT');
46
50
  }
47
51
 
48
52
 
@@ -68,27 +72,6 @@ export function firstFieldHasBetterPrepubEncodingLevel(field1, field2) {
68
72
  return false;
69
73
  }
70
74
 
71
- /*
72
- export function firstFieldHasEqualOrBetterPrepubEncodingLevel(field1, field2) {
73
- // Could be optimized...
74
- if (fieldRefersToKoneellisestiTuotettuTietue(field1)) {
75
- return true;
76
- }
77
- if (fieldRefersToKoneellisestiTuotettuTietue(field2)) {
78
- return false;
79
- }
80
- if (fieldRefersToTarkistettuEnnakkotieto(field1)) {
81
- return true;
82
- }
83
- if (fieldRefersToTarkistettuEnnakkotieto(field2)) {
84
- return false;
85
- }
86
- if (fieldRefersToEnnakkotieto(field1)) {
87
- return true;
88
- }
89
- return !fieldRefersToEnnakkotieto(field2);
90
- }
91
- */
92
75
 
93
76
  /*
94
77
  function hasEnnakkotietoSubfield(field) {
@@ -117,7 +100,7 @@ export function getRelevant5XXFields(record, f500 = false, f594 = false) {
117
100
 
118
101
  function hasRelevantPrepubData(field) {
119
102
  // Check prepub ($a):
120
- if (!fieldRefersToKoneellisestiTuotettuTietue(field) && !fieldRefersToEnnakkotieto(field)) {
103
+ if (!fieldRefersToKoneellisestiTuotettuTietue(field) && !fieldRefersToTarkistettuEnnakkotieto(field) && !fieldRefersToEnnakkotieto(field)) {
121
104
  return false;
122
105
  }
123
106
  // Check relevance (594$5):
@@ -209,7 +192,7 @@ export function deleteAllPrepublicationNotesFromField500InNonPubRecord(record) {
209
192
  return;
210
193
  }
211
194
 
212
- // MET-306: keep "koneellisesti tuotettu tietue" if encodng level is '2':
195
+ // MET-306: keep "koneellisesti tuotettu tietue" if encoding level is '2':
213
196
  const f500 = getRelevant5XXFields(record, true, false).filter(field => encodingLevel === '2' ? !fieldRefersToKoneellisestiTuotettuTietue(field) : true);
214
197
  if (f500.length === 0) {
215
198
  return;
@@ -117,7 +117,7 @@ const addX10bDot = {'name': 'Add X10 pre-$b dot', 'add': '.', 'code': 'ab', 'fol
117
117
  const addX10eComma = {'add': ',', 'code': 'abe', 'followedBy': 'e', 'context': defaultNeedsPuncAfter};
118
118
  const addX10Dot = {'name': 'Add X10 final dot', 'add': '.', 'code': 'abe', 'followedBy': '#', 'context': defaultNeedsPuncAfter};
119
119
  const addLanguageComma = {'name': 'Add comma before 810$l', 'add': ',', 'code': 'tv', 'followedBy': 'l', 'context': defaultNeedsPuncAfter2};
120
- const addColonToRelationshipInformation = {'name': 'Add \':\' to 7X0 $i relationship info', 'add': ':', 'code': 'i', 'context': /[a-z)åäö]$/u};
120
+ const addColonToRelationshipInformation = {'name': 'Add \':\' to 7X0 $i relationship info', 'add': ':', 'code': 'i', 'context': defaultNeedsPuncAfter2};
121
121
 
122
122
  // 490:
123
123
  const addSemicolonBeforeVolumeDesignation = {'name': 'Add " ;" before $v', 'add': ' ;', 'code': 'atxyz', 'followedBy': 'v', 'context': /[^;]$/u};
@@ -181,11 +181,12 @@ const cleanCrappyPunctuationRules = {
181
181
  const cleanLegalX00Comma = {'code': 'abcde', 'followedBy': 'cdegj', 'context': /.,$/u, 'remove': /,$/u};
182
182
  // Accept upper case letters in X00$b, since they are probably Roman numerals.
183
183
  const cleanLegalX00bDot = {'code': 'b', 'followedBy': 't#', context: /^[IVXLCDM]+\.$/u, 'remove': /\.$/u};
184
+ const cleanLegalX00iColon = {'code': 'i', 'followedBy': 'a', 'remove': / *:$/u}; // NB! context is not needed
184
185
  const cleanLegalX00Dot = {'code': 'abcdetvl', 'followedBy': 'tu#', 'context': /(?:[a-z0-9)]|å|ä|ö)\.$/u, 'remove': /\.$/u};
185
186
  const cleanLanguageComma = {'name': 'language comma', 'code': 'tv', 'followedBy': 'l', 'context': /.,$/u, 'remove': /,$/u};
186
187
 
187
188
 
188
- const legalX00punc = [cleanLegalX00Comma, cleanLegalX00bDot, cleanLegalX00Dot, cleanLanguageComma];
189
+ const legalX00punc = [cleanLegalX00Comma, cleanLegalX00iColon, cleanLegalX00bDot, cleanLegalX00Dot, cleanLanguageComma];
189
190
 
190
191
  const cleanLegalX10Comma = {'name': 'X10comma', 'code': 'abe', 'followedBy': 'e', 'context': /.,$/u, 'remove': /,$/u};
191
192
  const cleanLegalX10Dot = {'name': 'X10dot', 'code': 'ab', 'followedBy': 'b#', 'context': /.\.$/u, 'remove': /\.$/u};
@@ -176,6 +176,57 @@ export function removeInferiorChains(record, fix = true) {
176
176
  return deletedStringsArray;
177
177
  }
178
178
 
179
+ function deriveIndividualDeletables490(fieldAsString) {
180
+ if (!fieldAsString.match(/^490/u)) {
181
+ return [];
182
+ }
183
+
184
+ /* eslint-disable */
185
+ let deletable490s = [];
186
+
187
+ // $6-less version (keep this first)
188
+ let tmp = fieldAsString.replace(/ ‡6 [^‡]+ ‡/u, ' ‡');
189
+ if ( tmp !== fieldAsString) {
190
+ fieldAsString = tmp; // NB! Carry on with $6-less version!
191
+ deletable490s.push(tmp);
192
+ }
193
+
194
+ // Without final $v or $x:
195
+ tmp = fieldAsString.replace(/ *[;,] ‡[vx] [^‡]+$/u, '');
196
+ if ( tmp !== fieldAsString) {
197
+ deletable490s.push(tmp);
198
+ }
199
+
200
+ // Add intermedia $x-less version
201
+ tmp = fieldAsString.replace(/, ‡x [^‡]+(, ‡x| ; ‡v)/u, '$1');
202
+ // Add final $v/$x-less version
203
+ if ( tmp !== fieldAsString) {
204
+ deletable490s.push(tmp);
205
+ }
206
+
207
+ // Add $xv-less version
208
+ tmp = fieldAsString.replace(/, ‡x [^‡]+ ‡v [^‡]+$/u, '');
209
+ if ( tmp !== fieldAsString) {
210
+ deletable490s.push(tmp);
211
+ }
212
+
213
+ // MRA-433-ish (non-chain): 490 ind1=1 vs ind1=0: remove latter
214
+ if (fieldAsString.match(/^490 1/) ) {
215
+ // TODO: $x-less and $v-less versions...
216
+ tmp = `490 0${fieldAsString.substring(5)}`;
217
+ deletable490s.push(tmp);
218
+ const arr = deriveIndividualDeletables490(tmp);
219
+ arr.forEach(val => deletable490s.push(val));
220
+ }
221
+
222
+ nvdebug(`${deletable490s.length} derivation(s) for ${fieldAsString}`);
223
+ if (deletable490s.length > 0) {
224
+ nvdebug(deletable490s.join('\n'));
225
+ }
226
+ /* eslint-enable */
227
+ return deletable490s;
228
+ }
229
+
179
230
  function deriveIndividualDeletables(record) {
180
231
  /* eslint-disable */
181
232
  let deletableStringsArray = [];
@@ -187,7 +238,6 @@ function deriveIndividualDeletables(record) {
187
238
  function fieldDeriveIndividualDeletables(field) {
188
239
  const fieldAsString = fieldToString(field);
189
240
 
190
- nvdebug(`Derivations for ${fieldAsString}`);
191
241
  // Proof-of-concept rule:
192
242
  let tmp = fieldAsString;
193
243
  if (field.tag.match(/^[1678]00$/u)) {
@@ -197,22 +247,38 @@ function deriveIndividualDeletables(record) {
197
247
  }
198
248
  }
199
249
 
250
+ if (field.tag === '505') { // MRA-413-ish
251
+ if (fieldAsString.match(/^.0.*-- ‡t/u)) {
252
+ tmp = fieldAsString;
253
+ tmp = tmp.replace(/ -- ‡t /gu, ' -- ');
254
+ tmp = tmp.replace(/ ‡[rg] /gu, ' ');
255
+ tmp = tmp.replace(/ ‡t /u, ' ‡a '); // first $t, not
256
+ tmp = tmp.replace(/^505 (.)0/u, '505 $1#');
257
+ if (tmp !== fieldAsString) {
258
+ deletableStringsArray.push(tmp);
259
+ }
260
+ //nvdebug(`505 ORIGINAL: '${fieldAsString}'`)
261
+ //nvdebug(`505 DERIVATE: '${tmp}'`)
262
+ }
263
+ }
264
+
200
265
  // MET-381: remove occurence number TAG-00, if TAG-NN existists
201
266
  if (field.tag === '880') {
202
267
  tmp = fieldAsString;
203
268
  if (tmp.match(/ ‡6 [0-9][0-9][0-9]-(?:[1-9][0-9]|0[1-9])/)) {
204
269
  tmp = tmp.replace(/( ‡6 [0-9][0-9][0-9])-[0-9]+/, '$1-00');
205
- nvdebug(`MET-381: ADD TO DELETABLES: ${tmp}`);
270
+ nvdebug(`MET-381: ADD TO DELETABLES: '${tmp}'`);
206
271
  deletableStringsArray.push(tmp);
207
272
  if (tmp.match(/ ‡6 [0-9][0-9][0-9]-00\/[^ ]+ /)) {
208
273
  tmp = tmp.replace(/( ‡6 [0-9][0-9][0-9]-00)[^ ]+/, '$1');
209
- nvdebug(`MET-381: ADD TO DELETABLES: ${tmp}`);
274
+ nvdebug(`MET-381: ADD TO DELETABLES: '${tmp}'`);
210
275
  deletableStringsArray.push(tmp);
211
276
  }
212
277
  }
213
278
  }
214
279
 
215
-
280
+ const d490 = deriveIndividualDeletables490(fieldAsString);
281
+ d490.forEach(str => deletableStringsArray.push(str));
216
282
 
217
283
  // Remove keepless versions:
218
284
  tmp = fieldAsString;
@@ -221,13 +287,7 @@ function deriveIndividualDeletables(record) {
221
287
  deletableStringsArray.push(tmp);
222
288
  }
223
289
 
224
- // MRA-433-ish (non-chain): 490 ind1=1 vs ind1=0: remove latter
225
- if (fieldAsString.match(/^490 1/) ) {
226
- tmp = fieldAsString.replace(/^490 1/u, '490 0');
227
- deletableStringsArray.push(tmp);
228
- }
229
290
  }
230
-
231
291
  /* eslint-enable */
232
292
  return deletableStringsArray; // we should do uniq!
233
293
 
package/src/utils.js CHANGED
@@ -61,3 +61,15 @@ export function isControlSubfieldCode(subfieldCode) {
61
61
  }
62
62
  return false;
63
63
  }
64
+
65
+ export function getCatalogingLanguage(record) {
66
+ const [field040] = record.get(/^040$/u);
67
+ if (!field040) {
68
+ return null;
69
+ }
70
+ const [b] = field040.subfields.filter(sf => sf.code === 'b');
71
+ if (!b) {
72
+ return null;
73
+ }
74
+ return b.value;
75
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "message": [
3
+ "'TODO: 505 8# ‡a Foo ; Bar ; Lorum ; Ipsum' => '505 8# ‡a Foo -- Bar -- Lorum -- Ipsum'",
4
+ "'TODO: 505 80 ‡t Foo ; ‡t Bar ; ‡t Lorum ; ‡t Ipsum' => '505 80 ‡t Foo -- ‡t Bar -- ‡t Lorum -- ‡t Ipsum'"
5
+ ],
6
+ "valid": false
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "description": "Validate field 505 separators",
3
+ "comment": "NB! Handles only ' ; ' => ' -- ' conversions",
4
+ "enabled": true,
5
+ "fix": false,
6
+ "only": false
7
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "fields": [
3
+ {
4
+ "tag": "005",
5
+ "value": "20220202020202.0"
6
+ },
7
+ { "tag": "505", "ind1": "8", "ind2": " ", "subfields": [
8
+ { "code": "a", "value": "Foo ; Bar ; Lorum ; Ipsum" }
9
+ ]},
10
+ { "tag": "505", "ind1": "8", "ind2": " ", "subfields": [
11
+ { "code": "a", "value": "No -- action --required" }
12
+ ]},
13
+ { "tag": "505", "ind1": "8", "ind2": "0", "subfields": [
14
+ { "code": "t", "value": "Foo ;" },
15
+ { "code": "t", "value": "Bar ;" },
16
+ { "code": "t", "value": "Lorum ;" },
17
+ { "code": "t", "value": "Ipsum" }
18
+ ]},
19
+ { "tag": "505", "ind1": "8", "ind2": "0", "subfields": [
20
+ { "code": "t", "value": "Replace --" },
21
+ { "code": "t", "value": "only" },
22
+ { "code": "t", "value": "semicolon" }
23
+ ]}
24
+ ]
25
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "fields": [
4
+ {
5
+ "tag": "005",
6
+ "value": "20220202020202.0"
7
+ },
8
+ { "tag": "505", "ind1": "8", "ind2": " ", "subfields": [
9
+ { "code": "a", "value": "Foo -- Bar -- Lorum -- Ipsum" }
10
+ ]},
11
+ { "tag": "505", "ind1": "8", "ind2": " ", "subfields": [
12
+ { "code": "a", "value": "No -- action --required" }
13
+ ]},
14
+ { "tag": "505", "ind1": "8", "ind2": "0", "subfields": [
15
+ { "code": "t", "value": "Foo --" },
16
+ { "code": "t", "value": "Bar --" },
17
+ { "code": "t", "value": "Lorum --" },
18
+ { "code": "t", "value": "Ipsum" }
19
+ ]},
20
+ { "tag": "505", "ind1": "8", "ind2": "0", "subfields": [
21
+ { "code": "t", "value": "Replace --" },
22
+ { "code": "t", "value": "only" },
23
+ { "code": "t", "value": "semicolon" }
24
+ ]}
25
+ ],
26
+ "leader": ""
27
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "description": "Fix field 505 separators",
3
+ "comment": "NB! Handles only ' ; ' => ' -- ' conversions",
4
+ "enabled": true,
5
+ "fix": true,
6
+ "only": false
7
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "fields": [
3
+ {
4
+ "tag": "005",
5
+ "value": "20220202020202.0"
6
+ },
7
+ { "tag": "505", "ind1": "8", "ind2": " ", "subfields": [
8
+ { "code": "a", "value": "Foo ; Bar ; Lorum ; Ipsum" }
9
+ ]},
10
+ { "tag": "505", "ind1": "8", "ind2": " ", "subfields": [
11
+ { "code": "a", "value": "No -- action --required" }
12
+ ]},
13
+ { "tag": "505", "ind1": "8", "ind2": "0", "subfields": [
14
+ { "code": "t", "value": "Foo ;" },
15
+ { "code": "t", "value": "Bar ;" },
16
+ { "code": "t", "value": "Lorum ;" },
17
+ { "code": "t", "value": "Ipsum" }
18
+ ]},
19
+ { "tag": "505", "ind1": "8", "ind2": "0", "subfields": [
20
+ { "code": "t", "value": "Replace --" },
21
+ { "code": "t", "value": "only" },
22
+ { "code": "t", "value": "semicolon" }
23
+ ]}
24
+ ]
25
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "leader": "01331cam a22003494i 4500",
4
+ "fields": [
5
+ { "tag": "040", "ind1": " ", "ind2": " ", "subfields": [ { "code": "b", "value": "fin" } ] },
6
+ { "tag": "700", "ind1": " ", "ind2": " ",
7
+ "subfields": [
8
+ { "code": "a", "value": "Nimi," },
9
+ { "code": "e", "value": "säveltäjä,"},
10
+ { "code": "e", "value": "esittäjä,"},
11
+ { "code": "e", "value": "sanoittaja." }
12
+ ] }
13
+ ]
14
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "description": "F01: Fix relator terms: expand abbreviations based on 040$b",
3
+ "enabled": true,
4
+ "fix": true,
5
+ "only": false
6
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "leader": "01331cam a22003494i 4500",
3
+ "fields": [
4
+ { "tag": "040", "ind1": " ", "ind2": " ", "subfields": [ { "code": "b", "value": "fin" } ] },
5
+ { "tag": "700", "ind1": " ", "ind2": " ",
6
+ "subfields": [
7
+ { "code": "a", "value": "Nimi," },
8
+ { "code": "e", "value": "säv.,"},
9
+ { "code": "e", "value": "esitt.,"},
10
+ { "code": "e", "value": "san." }
11
+ ] }
12
+ ]
13
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "leader": "01331cam a22003494i 4500",
4
+ "fields": [
5
+ { "tag": "700", "ind1": " ", "ind2": " ",
6
+ "subfields": [
7
+ { "code": "a", "value": "Nimi," },
8
+ { "code": "e", "value": "esittäjä,"},
9
+ { "code": "e", "value": "sanoittaja." }
10
+ ] }
11
+ ]
12
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "description": "F01b: Fix relator terms: expand abbreviations (no 040$b)",
3
+ "enabled": true,
4
+ "fix": true,
5
+ "only": false
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "leader": "01331cam a22003494i 4500",
3
+ "fields": [
4
+ { "tag": "700", "ind1": " ", "ind2": " ",
5
+ "subfields": [
6
+ { "code": "a", "value": "Nimi," },
7
+ { "code": "e", "value": "esitt.,"},
8
+ { "code": "e", "value": "san." }
9
+ ] }
10
+ ]
11
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "leader": "01331cam a22003494i 4500",
4
+ "fields": [
5
+ { "tag": "040", "ind1": " ", "ind2": " ", "subfields": [ { "code": "b", "value": "fin" } ] },
6
+ { "tag": "700", "ind1": " ", "ind2": " ",
7
+ "subfields": [
8
+ { "code": "a", "value": "Nimi," },
9
+ { "code": "e", "value": "kirjoittaja."}
10
+ ] }
11
+ ]
12
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "description": "F02: Fix relator terms: expand abbreviations",
3
+ "enabled": true,
4
+ "fix": true,
5
+ "only": false
6
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "leader": "01331cam a22003494i 4500",
3
+ "fields": [
4
+ { "tag": "040", "ind1": " ", "ind2": " ", "subfields": [ { "code": "b", "value": "fin" } ] },
5
+ { "tag": "700", "ind1": " ", "ind2": " ",
6
+ "subfields": [
7
+ { "code": "a", "value": "Nimi," },
8
+ { "code": "e", "value": "författare."}
9
+ ] }
10
+ ]
11
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "message": [
3
+ "'TODO: 020 ## ‡a fv67890 ‡q häftad' => '020 ## ‡a fv67890 ‡q mjuka pärmar'",
4
+ "'TODO: 020 ## ‡a 1234567890 ‡q SID.' => '020 ## ‡a 1234567890 ‡q kovakantinen'",
5
+ "'TODO: 024 8# ‡a MEL123 ‡q Nidottu' => '024 8# ‡a MEL123 ‡q pehmeäkantinen'"
6
+ ],
7
+ "valid": false
8
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "description": "Validate qualifying information terms",
3
+ "comment": "MELINDA-8740",
4
+ "enabled": true,
5
+ "fix": false,
6
+ "only": false
7
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "fields": [
3
+ {
4
+ "tag": "005",
5
+ "value": "20220202020202.0"
6
+ },
7
+ { "tag": "020", "ind1": " ", "ind2": " ", "subfields": [
8
+ { "code": "a", "value": "fv67890" },
9
+ { "code": "q", "value": "häftad" }
10
+ ]},
11
+ { "tag": "020", "ind1": " ", "ind2": " ", "subfields": [
12
+ { "code": "a", "value": "1234567890" },
13
+ { "code": "q", "value": "SID." }
14
+ ]},
15
+ { "tag": "024", "ind1": "8", "ind2": " ", "subfields": [
16
+ { "code": "a", "value": "MEL123" },
17
+ { "code": "q", "value": "Nidottu" }
18
+ ]},
19
+ { "tag": "028", "ind1": "0", "ind2": " ", "subfields": [
20
+ { "code": "a", "value": "TätäEnVieläOsaa" },
21
+ { "code": "q", "value": "(sid.)" }
22
+ ]}
23
+
24
+ ]
25
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "_validationOptions": {},
3
+ "fields": [
4
+ {
5
+ "tag": "005",
6
+ "value": "20220202020202.0"
7
+ },
8
+ { "tag": "020", "ind1": " ", "ind2": " ", "subfields": [
9
+ { "code": "a", "value": "fv67890" },
10
+ { "code": "q", "value": "mjuka pärmar" }
11
+ ]},
12
+ { "tag": "020", "ind1": " ", "ind2": " ", "subfields": [
13
+ { "code": "a", "value": "1234567890" },
14
+ { "code": "q", "value": "kovakantinen" }
15
+ ]},
16
+ { "tag": "024", "ind1": "8", "ind2": " ", "subfields": [
17
+ { "code": "a", "value": "MEL123" },
18
+ { "code": "q", "value": "pehmeäkantinen" }
19
+ ]},
20
+ { "tag": "028", "ind1": "0", "ind2": " ", "subfields": [
21
+ { "code": "a", "value": "TätäEnVieläOsaa" },
22
+ { "code": "q", "value": "(sid.)" }
23
+ ]}
24
+
25
+ ],
26
+ "leader": ""
27
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "description": "Fix qualifying information terms",
3
+ "comment": "MELINDA-8740",
4
+ "enabled": true,
5
+ "fix": true,
6
+ "only": false
7
+ }