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

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 (69) hide show
  1. package/dist/ending-punctuation-conf.js +3 -6
  2. package/dist/ending-punctuation-conf.js.map +1 -1
  3. package/dist/index.js +7 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/punctuation/rules/aut.js +1 -2
  6. package/dist/punctuation/rules/aut.js.map +1 -1
  7. package/dist/punctuation/rules/bib.js +1 -2
  8. package/dist/punctuation/rules/bib.js.map +1 -1
  9. package/dist/punctuation2.js +40 -14
  10. package/dist/punctuation2.js.map +1 -1
  11. package/dist/removeInferiorDataFields.js +166 -168
  12. package/dist/removeInferiorDataFields.js.map +1 -1
  13. package/dist/sortFields.js +383 -0
  14. package/dist/sortFields.js.map +1 -0
  15. package/dist/sortFields.spec.js +51 -0
  16. package/dist/sortFields.spec.js.map +1 -0
  17. package/dist/sortRelatorTerms.js +3 -25
  18. package/dist/sortRelatorTerms.js.map +1 -1
  19. package/dist/sortSubfields.js +14 -4
  20. package/dist/sortSubfields.js.map +1 -1
  21. package/dist/sortSubfields.spec.js +4 -3
  22. package/dist/sortSubfields.spec.js.map +1 -1
  23. package/dist/utils.js +4 -0
  24. package/dist/utils.js.map +1 -1
  25. package/package.json +7 -7
  26. package/src/index.js +3 -1
  27. package/src/punctuation2.js +14 -7
  28. package/src/removeInferiorDataFields.js +166 -169
  29. package/src/sortFields.js +393 -0
  30. package/src/sortFields.spec.js +52 -0
  31. package/src/sortRelatorTerms.js +3 -25
  32. package/src/sortSubfields.js +18 -4
  33. package/src/sortSubfields.spec.js +3 -3
  34. package/src/utils.js +5 -0
  35. package/test-fixtures/remove-inferior-datafields/f01/expectedResult.json +12 -0
  36. package/test-fixtures/remove-inferior-datafields/f01/record.json +19 -0
  37. package/test-fixtures/sort-fields/01/input.json +32 -0
  38. package/test-fixtures/sort-fields/01/metadata.json +5 -0
  39. package/test-fixtures/sort-fields/01/result.json +29 -0
  40. package/test-fixtures/sort-fields/02/input.json +49 -0
  41. package/test-fixtures/sort-fields/02/metadata.json +4 -0
  42. package/test-fixtures/sort-fields/02/result.json +50 -0
  43. package/test-fixtures/sort-fields/03/input.json +20 -0
  44. package/test-fixtures/sort-fields/03/metadata.json +5 -0
  45. package/test-fixtures/sort-fields/03/result.json +21 -0
  46. package/test-fixtures/sort-fields/04/input.json +13 -0
  47. package/test-fixtures/sort-fields/04/metadata.json +4 -0
  48. package/test-fixtures/sort-fields/04/result.json +13 -0
  49. package/test-fixtures/sort-fields/05/input.json +27 -0
  50. package/test-fixtures/sort-fields/05/metadata.json +4 -0
  51. package/test-fixtures/sort-fields/05/result.json +28 -0
  52. package/test-fixtures/sort-fields/06/input.json +36 -0
  53. package/test-fixtures/sort-fields/06/metadata.json +4 -0
  54. package/test-fixtures/sort-fields/06/result.json +37 -0
  55. package/test-fixtures/sort-fields/07/input.json +21 -0
  56. package/test-fixtures/sort-fields/07/metadata.json +4 -0
  57. package/test-fixtures/sort-fields/07/result.json +22 -0
  58. package/test-fixtures/sort-fields/08/input.json +29 -0
  59. package/test-fixtures/sort-fields/08/metadata.json +5 -0
  60. package/test-fixtures/sort-fields/08/result.json +29 -0
  61. package/test-fixtures/sort-fields/09/input.json +41 -0
  62. package/test-fixtures/sort-fields/09/metadata.json +5 -0
  63. package/test-fixtures/sort-fields/09/result.json +42 -0
  64. package/test-fixtures/sort-fields/10/input.json +54 -0
  65. package/test-fixtures/sort-fields/10/metadata.json +5 -0
  66. package/test-fixtures/sort-fields/10/result.json +53 -0
  67. package/test-fixtures/sort-subfields/f02/expectedResult.json +26 -0
  68. package/test-fixtures/sort-subfields/f02/metadata.json +7 -0
  69. package/test-fixtures/sort-subfields/f02/record.json +25 -0
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = _default;
7
+ exports.fieldOrderComparator = fieldOrderComparator;
8
+ exports.relatorTermScore = void 0;
9
+ exports.scoreRelatorTerm = scoreRelatorTerm;
10
+ var _clone = _interopRequireDefault(require("clone"));
11
+ var _debug = _interopRequireDefault(require("debug"));
12
+ var _utils = require("./utils");
13
+ var _subfield8Utils = require("./subfield8Utils");
14
+ var _subfield6Utils = require("./subfield6Utils");
15
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
+ // Taken from project marc-record-js, file marcSortFields.js as this contains more and more Melinda-specific rules.
17
+
18
+ const BIG_BAD_NUMBER = 999.99;
19
+ const debug = (0, _debug.default)('@natlibfi/marc-record-validators-melinda:sortFields');
20
+ //const debugData = debug.extend('data');
21
+ const debugDev = debug.extend('dev');
22
+ function _default() {
23
+ return {
24
+ description: 'Sort fields',
25
+ validate,
26
+ fix
27
+ };
28
+ function fix(record) {
29
+ const res = {
30
+ message: [],
31
+ fix: [],
32
+ valid: true
33
+ };
34
+ record.fields.sort(fieldOrderComparator); // eslint-disable-line functional/immutable-data
35
+
36
+ return res;
37
+ }
38
+ function validate(record) {
39
+ const res = {
40
+ message: []
41
+ };
42
+ const fields = record.fields.map(f => (0, _clone.default)(f));
43
+ fields.sort(fieldOrderComparator); // eslint-disable-line functional/immutable-data
44
+
45
+ const relocatedFields = fields.filter((f, i) => (0, _utils.fieldToString)(f) !== (0, _utils.fieldToString)(record.fields[i]));
46
+ if (relocatedFields.length > 0) {
47
+ // eslint-disable-line functional/no-conditional-statements
48
+ res.message.push(`${relocatedFields.length} field(s) in new places`); // eslint-disable-line functional/immutable-data
49
+ }
50
+
51
+ res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data
52
+ return res;
53
+ }
54
+ }
55
+ const relatorTermScore = exports.relatorTermScore = {
56
+ // Here bigger is better
57
+ // NB! This is exportable as field internal $e sorting in marc-record-validators-js uses this.
58
+ // NB! The more abstract, the earlier it appears.
59
+ // Note that terms with same abstraction level might also have order preferences
60
+ // We should 1) check the order of these, and 2) add translations (support Swedish at the very least)
61
+ // work/teos > expression/ekspressio > manifestation/manifestaatio
62
+ 'säveltäjä': 100,
63
+ 'composer': 100,
64
+ 'kirjoittaja': 99,
65
+ 'author': 100,
66
+ 'sarjakuvantekijä': 99,
67
+ 'taiteilija': 98,
68
+ 'sanoittaja': 90,
69
+ 'käsikirjoittaja': 90,
70
+ // expression:
71
+ 'toimittaja': 80,
72
+ 'editor': 80,
73
+ 'sovittaja': 80,
74
+ 'arranger': 80,
75
+ 'kuvittaja': 75,
76
+ 'editointi': 71,
77
+ // for music, editor/toimittaja is another thing
78
+ 'kääntäjä': 70,
79
+ 'lukija': 61,
80
+ // Manifestation level
81
+ 'esittäjä': 60,
82
+ 'johtaja': 50,
83
+ // orkesterinjohtaja
84
+ 'kustantaja': 41,
85
+ 'julkaisija': 40
86
+ };
87
+ function scoreRelatorTerm(value) {
88
+ // sortRelatorTerms.js validator should call this on future version
89
+ const normValue = value.replace(/[.,]+$/u, '');
90
+ if (normValue in relatorTermScore) {
91
+ return relatorTermScore[normValue];
92
+ }
93
+ return 0;
94
+ }
95
+ function fieldOrderComparator(fieldA, fieldB) {
96
+ const sorterFunctions = [sortByTag, sortByIndexTerms, sortAlphabetically, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];
97
+ for (const sortFn of sorterFunctions) {
98
+ // eslint-disable-line functional/no-loop-statements
99
+ const result = sortFn(fieldA, fieldB);
100
+ debugDev(`${sortFn.name}: '${(0, _utils.fieldToString)(fieldA)}' vs '${(0, _utils.fieldToString)(fieldB)}': ${result}`);
101
+ if (result !== 0) {
102
+ return result;
103
+ }
104
+ }
105
+ return 0;
106
+ function sortByTag(fieldA, fieldB) {
107
+ function getSortIndex(tag) {
108
+ const sortIndex = {
109
+ LDR: '000',
110
+ STA: '001.1',
111
+ // STA comes now after 001. However 003+001 form a combo, so I'm not sure...
112
+ SID: '999.1',
113
+ LOW: '999.2',
114
+ CAT: '999.3',
115
+ HLI: '999.4'
116
+ };
117
+ if (tag in sortIndex) {
118
+ // <- this allows weights for numeric values as well (not that we use them yet)
119
+ return sortIndex[tag];
120
+ }
121
+ if (isNaN(tag)) {
122
+ return '999.9';
123
+ }
124
+ return tag;
125
+ }
126
+ const orderA = getSortIndex(fieldA.tag);
127
+ const orderB = getSortIndex(fieldB.tag);
128
+ if (orderA > orderB) {
129
+ return 1;
130
+ }
131
+ if (orderA < orderB) {
132
+ return -1;
133
+ }
134
+ return 0;
135
+ }
136
+ function sortByIndexTerms(fieldA, fieldB) {
137
+ // eslint-disable-line complexity, max-statements
138
+
139
+ const indexTermFields = ['600', '610', '611', '630', '648', '650', '651', '652', '653', '654', '655', '656', '657', '658', '659', '662'];
140
+ function scoreInd2(val) {
141
+ const ind2Score = {
142
+ '0': 0,
143
+ '1': 1,
144
+ '2': 2,
145
+ '3': 3,
146
+ '4': 8,
147
+ '5': 5,
148
+ '6': 6,
149
+ '7': 7
150
+ };
151
+ if (val in ind2Score) {
152
+ return ind2Score[val];
153
+ }
154
+ return 9;
155
+ }
156
+
157
+ // ATM this is not needed.
158
+ // You may need this, if you change compare function order in sorterFunctions
159
+ // istanbul ignore next
160
+ if (fieldA.tag !== fieldB.tag) {
161
+ return 0;
162
+ }
163
+ if (!indexTermFields.includes(fieldA.tag)) {
164
+ return 0;
165
+ }
166
+
167
+ /* Puts ind2=4 last */
168
+ if (scoreInd2(fieldA.ind2) > scoreInd2(fieldB.ind2)) {
169
+ return 1;
170
+ }
171
+ if (scoreInd2(fieldA.ind2) < scoreInd2(fieldB.ind2)) {
172
+ return -1;
173
+ }
174
+ function scoreDictionary(dictionary) {
175
+ const dictionarySortIndex = {
176
+ 'yso/fin': 0,
177
+ 'yso/swe': 1,
178
+ 'yso/eng': 2,
179
+ 'slm/fin': 0.1,
180
+ 'slm/swe': 1.1,
181
+ 'kauno/fin': 2.1,
182
+ 'kauno/swe': 2.2,
183
+ 'kaunokki': 4,
184
+ 'bella': 5
185
+ };
186
+ if (dictionary in dictionarySortIndex) {
187
+ return dictionarySortIndex[dictionary];
188
+ }
189
+ return BIG_BAD_NUMBER;
190
+ }
191
+ const dictionaryA = selectFirstValue(fieldA, '2');
192
+ const dictionaryB = selectFirstValue(fieldB, '2');
193
+ const dictScoreA = scoreDictionary(dictionaryA);
194
+ const dictScoreB = scoreDictionary(dictionaryB);
195
+ // Use priority order for listed dictionaries:
196
+ if (dictScoreA > dictScoreB) {
197
+ return 1;
198
+ }
199
+ if (dictScoreA < dictScoreB) {
200
+ return -1;
201
+ }
202
+ // Unlisted dictionaries: sort $2 value alphabetically:
203
+ //if (dictScoreA === BIG_BAD_NUMBER) {
204
+ if (dictionaryA > dictionaryB) {
205
+ return 1;
206
+ }
207
+ if (dictionaryA < dictionaryB) {
208
+ return -1;
209
+ }
210
+ //}
211
+ return 0;
212
+ }
213
+ function preferKeep(fieldA, fieldB, keepOwner = 'FENNI') {
214
+ const hasKeepA = (0, _utils.fieldHasSubfield)(fieldA, '9', `${keepOwner}<KEEP>`);
215
+ const hasKeepB = (0, _utils.fieldHasSubfield)(fieldB, '9', `${keepOwner}<KEEP>`);
216
+ if (hasKeepA && !hasKeepB) {
217
+ return -1;
218
+ }
219
+ if (!hasKeepA && hasKeepB) {
220
+ return 1;
221
+ }
222
+ return 0;
223
+ }
224
+ function preferFenniKeep(fieldA, fieldB) {
225
+ const fenniPreference = preferKeep(fieldA, fieldB, 'FENNI');
226
+ if (fenniPreference !== 0) {
227
+ return fenniPreference;
228
+ }
229
+ const violaPreference = preferKeep(fieldA, fieldB, 'VIOLA');
230
+ if (violaPreference !== 0) {
231
+ return violaPreference;
232
+ }
233
+ return preferKeep(fieldA, fieldB, 'FIKKA');
234
+ }
235
+ function sortByRelatorTerm(fieldA, fieldB) {
236
+ // Should this be done to 6XX and 8XX fields as well? Does $t affect sorting?
237
+ if (!['700', '710', '711', '730'].includes(fieldA.tag)) {
238
+ return 0;
239
+ }
240
+ function fieldGetMaxRelatorTermScore(field) {
241
+ if (!field.subfields) {
242
+ return 0;
243
+ }
244
+ const e = field.subfields.filter(sf => sf.code === 'e');
245
+ const scores = e.map(sf => scoreRelatorTerm(sf.value));
246
+ //debugDev(`RELATOR SCORE FOR '${fieldToString(field)}': ${scores.join(', ')}`);
247
+ return Math.max(...scores);
248
+ }
249
+ const scoreA = fieldGetMaxRelatorTermScore(fieldA);
250
+ const scoreB = fieldGetMaxRelatorTermScore(fieldB);
251
+ if (scoreA < scoreB) {
252
+ return 1;
253
+ }
254
+ if (scoreA > scoreB) {
255
+ return -1;
256
+ }
257
+ return 0;
258
+ }
259
+ function fieldGetMinLinkAndSequenceNumber(field) {
260
+ if (!field.subfields) {
261
+ return BIG_BAD_NUMBER;
262
+ }
263
+ const relevantSubfields = field.subfields.filter(sf => (0, _subfield8Utils.isValidSubfield8)(sf));
264
+ // If val is something like "1.2\x" parseFloat() would give a syntax erro because of hex-like escape sequnce (at least on Chrome). Thus remove tail:
265
+ const scores = relevantSubfields.map(sf => parseFloat(sf.value.replace(/\\.*$/u, '')));
266
+ if (scores.length === 0) {
267
+ return BIG_BAD_NUMBER;
268
+ }
269
+ return Math.min(...scores);
270
+ }
271
+ function sortByFieldLinkAndSequenceNumber(fieldA, fieldB) {
272
+ // Sort by subfield $8 that is...
273
+ const scoreA = fieldGetMinLinkAndSequenceNumber(fieldA);
274
+ const scoreB = fieldGetMinLinkAndSequenceNumber(fieldB);
275
+ //debugDev(` sf-8-A-score for '${fieldToString(fieldA)}: ${scoreA}`);
276
+ //debugDev(` sf-8-B-score for '${fieldToString(fieldB)}: ${scoreB}`);
277
+ if (scoreA === scoreB) {
278
+ return 0;
279
+ }
280
+ if (scoreB === 0) {
281
+ return 1;
282
+ }
283
+ if (scoreA === 0) {
284
+ return -1;
285
+ }
286
+ if (scoreA > scoreB) {
287
+ // smaller is better
288
+ return 1;
289
+ }
290
+ return -1;
291
+ }
292
+ function sortByOccurrenceNumber(fieldA, fieldB) {
293
+ // Sort by subfield $6
294
+
295
+ function fieldGetOccurrenceNumber(field) {
296
+ // should this function be exported? (based on validator sortRelatorFields.js)
297
+ if (!field.subfields) {
298
+ return 0;
299
+ }
300
+ const subfield6 = field.subfields.find(sf => (0, _subfield6Utils.isValidSubfield6)(sf));
301
+ if (subfield6 === undefined) {
302
+ return 0;
303
+ }
304
+ return parseInt((0, _subfield6Utils.subfield6GetOccurrenceNumber)(subfield6), 10);
305
+ }
306
+ if (fieldA.tag !== '880') {
307
+ return 0;
308
+ }
309
+ const scoreA = fieldGetOccurrenceNumber(fieldA);
310
+ const scoreB = fieldGetOccurrenceNumber(fieldB);
311
+
312
+ //debugDev(`A: '${fieldToString(fieldA)}: ${scoreA}`);
313
+ //debugDev(`B: '${fieldToString(fieldB)}: ${scoreB}`);
314
+
315
+ if (scoreA === scoreB) {
316
+ return 0;
317
+ }
318
+ if (scoreB === 0) {
319
+ return -1;
320
+ }
321
+ if (scoreA === 0) {
322
+ return 1;
323
+ }
324
+ if (scoreA > scoreB) {
325
+ // smaller is better
326
+ return 1;
327
+ }
328
+ return -1;
329
+ }
330
+ function sortAlphabetically(fieldA, fieldB) {
331
+ const tagToSortingSubfields = {
332
+ // '028': ['b', 'a']?
333
+ 'LOW': ['a'],
334
+ 'SID': ['c']
335
+ };
336
+ function scoreSubfieldsAlphabetically(setOfSubfields) {
337
+ if (setOfSubfields.length === 0) {
338
+ return 0;
339
+ }
340
+ const [subfieldCode, ...remainingSubfieldCodes] = setOfSubfields;
341
+ const valA = selectFirstValue(fieldA, subfieldCode);
342
+ const valB = selectFirstValue(fieldB, subfieldCode);
343
+ //debugDev(`CHECKING SUBFIELD '${subfieldCode}'`);
344
+ if (!valA) {
345
+ if (!valB) {
346
+ return scoreSubfieldsAlphabetically(remainingSubfieldCodes);
347
+ }
348
+ return -1;
349
+ }
350
+ if (!valB) {
351
+ return 1;
352
+ }
353
+ //debugDev(`CHECKING SUBFIELD '${subfieldCode}': '${valA}' vs '${valB}'`);
354
+
355
+ if (valA < valB) {
356
+ return -1;
357
+ }
358
+ if (valB < valA) {
359
+ return 1;
360
+ }
361
+ return scoreSubfieldsAlphabetically(remainingSubfieldCodes);
362
+ }
363
+ if (fieldA.tag === fieldB.tag) {
364
+ if (!(fieldA.tag in tagToSortingSubfields)) {
365
+ return 0;
366
+ }
367
+ const subfieldsToCheck = tagToSortingSubfields[fieldA.tag];
368
+
369
+ //debugDev(`CHECKING ${subfieldsToCheck.join(', ')}`);
370
+ const result = scoreSubfieldsAlphabetically(subfieldsToCheck);
371
+ //debugDev(`RESULT ${result}`);
372
+ return result;
373
+ }
374
+ return 0;
375
+ }
376
+
377
+ //-----------------------------------------------------------------------------
378
+
379
+ function selectFirstValue(field, subcode) {
380
+ return field.subfields.filter(subfield => subcode === subfield.code).map(subfield => subfield.value).slice(0, 1);
381
+ }
382
+ }
383
+ //# sourceMappingURL=sortFields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortFields.js","names":["_clone","_interopRequireDefault","require","_debug","_utils","_subfield8Utils","_subfield6Utils","obj","__esModule","default","BIG_BAD_NUMBER","debug","createDebugLogger","debugDev","extend","_default","description","validate","fix","record","res","message","valid","fields","sort","fieldOrderComparator","map","f","clone","relocatedFields","filter","i","fieldToString","length","push","relatorTermScore","exports","scoreRelatorTerm","value","normValue","replace","fieldA","fieldB","sorterFunctions","sortByTag","sortByIndexTerms","sortAlphabetically","sortByRelatorTerm","sortByOccurrenceNumber","preferFenniKeep","sortByFieldLinkAndSequenceNumber","sortFn","result","name","getSortIndex","tag","sortIndex","LDR","STA","SID","LOW","CAT","HLI","isNaN","orderA","orderB","indexTermFields","scoreInd2","val","ind2Score","includes","ind2","scoreDictionary","dictionary","dictionarySortIndex","dictionaryA","selectFirstValue","dictionaryB","dictScoreA","dictScoreB","preferKeep","keepOwner","hasKeepA","fieldHasSubfield","hasKeepB","fenniPreference","violaPreference","fieldGetMaxRelatorTermScore","field","subfields","e","sf","code","scores","Math","max","scoreA","scoreB","fieldGetMinLinkAndSequenceNumber","relevantSubfields","isValidSubfield8","parseFloat","min","fieldGetOccurrenceNumber","subfield6","find","isValidSubfield6","undefined","parseInt","subfield6GetOccurrenceNumber","tagToSortingSubfields","scoreSubfieldsAlphabetically","setOfSubfields","subfieldCode","remainingSubfieldCodes","valA","valB","subfieldsToCheck","subcode","subfield","slice"],"sources":["../src/sortFields.js"],"sourcesContent":["// Taken from project marc-record-js, file marcSortFields.js as this contains more and more Melinda-specific rules.\n\nimport clone from 'clone';\nimport createDebugLogger from 'debug';\nimport {fieldHasSubfield, fieldToString} from './utils';\nimport {isValidSubfield8} from './subfield8Utils';\nimport {isValidSubfield6, subfield6GetOccurrenceNumber} from './subfield6Utils';\n\n\nconst BIG_BAD_NUMBER = 999.99;\n\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortFields');\n//const debugData = debug.extend('data');\nconst debugDev = debug.extend('dev');\n\nexport default function () {\n\n return {\n description: 'Sort fields',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n record.fields.sort(fieldOrderComparator); // eslint-disable-line functional/immutable-data\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n const fields = record.fields.map(f => clone(f));\n fields.sort(fieldOrderComparator); // eslint-disable-line functional/immutable-data\n\n\n const relocatedFields = fields.filter((f, i) => fieldToString(f) !== fieldToString(record.fields[i]));\n\n if (relocatedFields.length > 0) { // eslint-disable-line functional/no-conditional-statements\n res.message.push(`${relocatedFields.length} field(s) in new places`); // eslint-disable-line functional/immutable-data\n }\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\n\nexport const relatorTermScore = { // Here bigger is better\n // NB! This is exportable as field internal $e sorting in marc-record-validators-js uses this.\n // NB! The more abstract, the earlier it appears.\n // Note that terms with same abstraction level might also have order preferences\n // We should 1) check the order of these, and 2) add translations (support Swedish at the very least)\n // work/teos > expression/ekspressio > manifestation/manifestaatio\n 'säveltäjä': 100, 'composer': 100,\n 'kirjoittaja': 99, 'author': 100,\n 'sarjakuvantekijä': 99,\n 'taiteilija': 98,\n 'sanoittaja': 90,\n 'käsikirjoittaja': 90,\n // expression:\n 'toimittaja': 80, 'editor': 80,\n 'sovittaja': 80, 'arranger': 80,\n 'kuvittaja': 75,\n 'editointi': 71, // for music, editor/toimittaja is another thing\n 'kääntäjä': 70,\n 'lukija': 61,\n // Manifestation level\n 'esittäjä': 60,\n 'johtaja': 50, // orkesterinjohtaja\n 'kustantaja': 41,\n 'julkaisija': 40\n\n};\n\nexport function scoreRelatorTerm(value) { // sortRelatorTerms.js validator should call this on future version\n const normValue = value.replace(/[.,]+$/u, '');\n if (normValue in relatorTermScore) {\n return relatorTermScore[normValue];\n }\n return 0;\n}\n\nexport function fieldOrderComparator(fieldA, fieldB) {\n\n const sorterFunctions = [sortByTag, sortByIndexTerms, sortAlphabetically, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];\n\n for (const sortFn of sorterFunctions) { // eslint-disable-line functional/no-loop-statements\n const result = sortFn(fieldA, fieldB);\n debugDev(`${sortFn.name}: '${fieldToString(fieldA)}' vs '${fieldToString(fieldB)}': ${result}`);\n if (result !== 0) {\n return result;\n }\n }\n\n return 0;\n\n function sortByTag(fieldA, fieldB) {\n\n function getSortIndex(tag) {\n const sortIndex = {\n LDR: '000',\n STA: '001.1', // STA comes now after 001. However 003+001 form a combo, so I'm not sure...\n SID: '999.1',\n LOW: '999.2',\n CAT: '999.3',\n HLI: '999.4'\n };\n\n if (tag in sortIndex) { // <- this allows weights for numeric values as well (not that we use them yet)\n return sortIndex[tag];\n }\n if (isNaN(tag)) {\n return '999.9';\n }\n return tag;\n }\n\n const orderA = getSortIndex(fieldA.tag);\n const orderB = getSortIndex(fieldB.tag);\n\n if (orderA > orderB) {\n return 1;\n }\n if (orderA < orderB) {\n return -1;\n }\n\n return 0;\n }\n\n function sortByIndexTerms(fieldA, fieldB) { // eslint-disable-line complexity, max-statements\n\n const indexTermFields = ['600', '610', '611', '630', '648', '650', '651', '652', '653', '654', '655', '656', '657', '658', '659', '662'];\n\n function scoreInd2(val) {\n const ind2Score = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 8, '5': 5, '6': 6, '7': 7};\n\n if (val in ind2Score) {\n return ind2Score[val];\n }\n return 9;\n }\n\n // ATM this is not needed.\n // You may need this, if you change compare function order in sorterFunctions\n // istanbul ignore next\n if (fieldA.tag !== fieldB.tag) {\n return 0;\n }\n\n if (!indexTermFields.includes(fieldA.tag)) {\n return 0;\n }\n\n /* Puts ind2=4 last */\n if (scoreInd2(fieldA.ind2) > scoreInd2(fieldB.ind2)) {\n return 1;\n }\n if (scoreInd2(fieldA.ind2) < scoreInd2(fieldB.ind2)) {\n return -1;\n }\n\n function scoreDictionary(dictionary) {\n const dictionarySortIndex = {\n 'yso/fin': 0,\n 'yso/swe': 1,\n 'yso/eng': 2,\n 'slm/fin': 0.1,\n 'slm/swe': 1.1,\n 'kauno/fin': 2.1,\n 'kauno/swe': 2.2,\n 'kaunokki': 4,\n 'bella': 5\n };\n\n if (dictionary in dictionarySortIndex) {\n return dictionarySortIndex[dictionary];\n }\n return BIG_BAD_NUMBER;\n }\n\n const dictionaryA = selectFirstValue(fieldA, '2');\n const dictionaryB = selectFirstValue(fieldB, '2');\n\n const dictScoreA = scoreDictionary(dictionaryA);\n const dictScoreB = scoreDictionary(dictionaryB);\n // Use priority order for listed dictionaries:\n if (dictScoreA > dictScoreB) {\n return 1;\n }\n if (dictScoreA < dictScoreB) {\n return -1;\n }\n // Unlisted dictionaries: sort $2 value alphabetically:\n //if (dictScoreA === BIG_BAD_NUMBER) {\n if (dictionaryA > dictionaryB) {\n return 1;\n }\n if (dictionaryA < dictionaryB) {\n return -1;\n }\n //}\n return 0;\n }\n\n function preferKeep(fieldA, fieldB, keepOwner = 'FENNI') {\n const hasKeepA = fieldHasSubfield(fieldA, '9', `${keepOwner}<KEEP>`);\n const hasKeepB = fieldHasSubfield(fieldB, '9', `${keepOwner}<KEEP>`);\n\n if (hasKeepA && !hasKeepB) {\n return -1;\n }\n if (!hasKeepA && hasKeepB) {\n return 1;\n }\n\n return 0;\n }\n\n function preferFenniKeep(fieldA, fieldB) {\n const fenniPreference = preferKeep(fieldA, fieldB, 'FENNI');\n if (fenniPreference !== 0) {\n return fenniPreference;\n }\n const violaPreference = preferKeep(fieldA, fieldB, 'VIOLA');\n if (violaPreference !== 0) {\n return violaPreference;\n }\n return preferKeep(fieldA, fieldB, 'FIKKA');\n }\n\n function sortByRelatorTerm(fieldA, fieldB) {\n // Should this be done to 6XX and 8XX fields as well? Does $t affect sorting?\n if (!['700', '710', '711', '730'].includes(fieldA.tag)) {\n return 0;\n }\n\n\n function fieldGetMaxRelatorTermScore(field) {\n if (!field.subfields) {\n return 0;\n }\n const e = field.subfields.filter(sf => sf.code === 'e');\n const scores = e.map(sf => scoreRelatorTerm(sf.value));\n //debugDev(`RELATOR SCORE FOR '${fieldToString(field)}': ${scores.join(', ')}`);\n return Math.max(...scores);\n }\n\n const scoreA = fieldGetMaxRelatorTermScore(fieldA);\n const scoreB = fieldGetMaxRelatorTermScore(fieldB);\n\n if (scoreA < scoreB) {\n return 1;\n }\n if (scoreA > scoreB) {\n return -1;\n }\n return 0;\n }\n\n function fieldGetMinLinkAndSequenceNumber(field) {\n if (!field.subfields) {\n return BIG_BAD_NUMBER;\n }\n const relevantSubfields = field.subfields.filter(sf => isValidSubfield8(sf));\n // If val is something like \"1.2\\x\" parseFloat() would give a syntax erro because of hex-like escape sequnce (at least on Chrome). Thus remove tail:\n const scores = relevantSubfields.map(sf => parseFloat(sf.value.replace(/\\\\.*$/u, '')));\n if (scores.length === 0) {\n return BIG_BAD_NUMBER;\n }\n return Math.min(...scores);\n }\n\n function sortByFieldLinkAndSequenceNumber(fieldA, fieldB) { // Sort by subfield $8 that is...\n const scoreA = fieldGetMinLinkAndSequenceNumber(fieldA);\n const scoreB = fieldGetMinLinkAndSequenceNumber(fieldB);\n //debugDev(` sf-8-A-score for '${fieldToString(fieldA)}: ${scoreA}`);\n //debugDev(` sf-8-B-score for '${fieldToString(fieldB)}: ${scoreB}`);\n if (scoreA === scoreB) {\n return 0;\n }\n if (scoreB === 0) {\n return 1;\n }\n if (scoreA === 0) {\n return -1;\n }\n if (scoreA > scoreB) { // smaller is better\n return 1;\n }\n return -1;\n }\n\n function sortByOccurrenceNumber(fieldA, fieldB) { // Sort by subfield $6\n\n function fieldGetOccurrenceNumber(field) { // should this function be exported? (based on validator sortRelatorFields.js)\n if (!field.subfields) {\n return 0;\n }\n const subfield6 = field.subfields.find(sf => isValidSubfield6(sf));\n if (subfield6 === undefined) {\n return 0;\n }\n return parseInt(subfield6GetOccurrenceNumber(subfield6), 10);\n }\n\n if (fieldA.tag !== '880') {\n return 0;\n }\n const scoreA = fieldGetOccurrenceNumber(fieldA);\n const scoreB = fieldGetOccurrenceNumber(fieldB);\n\n //debugDev(`A: '${fieldToString(fieldA)}: ${scoreA}`);\n //debugDev(`B: '${fieldToString(fieldB)}: ${scoreB}`);\n\n if (scoreA === scoreB) {\n return 0;\n }\n if (scoreB === 0) {\n return -1;\n }\n if (scoreA === 0) {\n return 1;\n }\n if (scoreA > scoreB) { // smaller is better\n return 1;\n }\n return -1;\n }\n\n function sortAlphabetically(fieldA, fieldB) {\n const tagToSortingSubfields = {\n // '028': ['b', 'a']?\n 'LOW': ['a'],\n 'SID': ['c']\n };\n\n function scoreSubfieldsAlphabetically(setOfSubfields) {\n if (setOfSubfields.length === 0) {\n return 0;\n }\n const [subfieldCode, ...remainingSubfieldCodes] = setOfSubfields;\n const valA = selectFirstValue(fieldA, subfieldCode);\n const valB = selectFirstValue(fieldB, subfieldCode);\n //debugDev(`CHECKING SUBFIELD '${subfieldCode}'`);\n if (!valA) {\n if (!valB) {\n return scoreSubfieldsAlphabetically(remainingSubfieldCodes);\n }\n return -1;\n }\n if (!valB) {\n return 1;\n }\n //debugDev(`CHECKING SUBFIELD '${subfieldCode}': '${valA}' vs '${valB}'`);\n\n if (valA < valB) {\n return -1;\n }\n if (valB < valA) {\n return 1;\n }\n return scoreSubfieldsAlphabetically(remainingSubfieldCodes);\n }\n\n if (fieldA.tag === fieldB.tag) {\n if (!(fieldA.tag in tagToSortingSubfields)) {\n return 0;\n }\n\n const subfieldsToCheck = tagToSortingSubfields[fieldA.tag];\n\n //debugDev(`CHECKING ${subfieldsToCheck.join(', ')}`);\n const result = scoreSubfieldsAlphabetically(subfieldsToCheck);\n //debugDev(`RESULT ${result}`);\n return result;\n }\n return 0;\n }\n\n //-----------------------------------------------------------------------------\n\n\n function selectFirstValue(field, subcode) {\n return field.subfields\n .filter(subfield => subcode === subfield.code)\n .map(subfield => subfield.value)\n .slice(0, 1);\n }\n}\n\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+
3
+ var _chai = require("chai");
4
+ var _marcRecord = require("@natlibfi/marc-record");
5
+ var _sortFields = _interopRequireDefault(require("./sortFields"));
6
+ var _fixura = require("@natlibfi/fixura");
7
+ var _fixugen = _interopRequireDefault(require("@natlibfi/fixugen"));
8
+ var _debug = _interopRequireDefault(require("debug"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ (0, _fixugen.default)({
11
+ callback,
12
+ path: [__dirname, '..', 'test-fixtures', 'sort-fields'],
13
+ useMetadataFile: true,
14
+ recurse: false,
15
+ fixura: {
16
+ reader: _fixura.READERS.JSON
17
+ },
18
+ mocha: {
19
+ before: () => testValidatorFactory()
20
+ }
21
+ });
22
+ const debug = (0, _debug.default)('@natlibfi/marc-record-validators-melinda/sortFields:test');
23
+ async function testValidatorFactory() {
24
+ const validator = await (0, _sortFields.default)();
25
+ (0, _chai.expect)(validator).to.be.an('object').that.has.any.keys('description', 'validate');
26
+ (0, _chai.expect)(validator.description).to.be.a('string');
27
+ (0, _chai.expect)(validator.validate).to.be.a('function');
28
+ }
29
+ async function callback({
30
+ getFixture,
31
+ enabled = true,
32
+ fix = true
33
+ }) {
34
+ if (enabled === false) {
35
+ debug('TEST SKIPPED!');
36
+ return;
37
+ }
38
+ const validator = await (0, _sortFields.default)();
39
+ const record = new _marcRecord.MarcRecord(getFixture('input.json'));
40
+ const expectedResult = getFixture('result.json');
41
+ // console.log(expectedResult); // eslint-disable-line
42
+
43
+ if (!fix) {
44
+ const result = await validator.validate(record);
45
+ (0, _chai.expect)(result).to.eql(expectedResult);
46
+ return;
47
+ }
48
+ await validator.fix(record);
49
+ (0, _chai.expect)(record).to.eql(expectedResult);
50
+ }
51
+ //# sourceMappingURL=sortFields.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sortFields.spec.js","names":["_chai","require","_marcRecord","_sortFields","_interopRequireDefault","_fixura","_fixugen","_debug","obj","__esModule","default","generateTests","callback","path","__dirname","useMetadataFile","recurse","fixura","reader","READERS","JSON","mocha","before","testValidatorFactory","debug","createDebugLogger","validator","validatorFactory","expect","to","be","an","that","has","any","keys","description","a","validate","getFixture","enabled","fix","record","MarcRecord","expectedResult","result","eql"],"sources":["../src/sortFields.spec.js"],"sourcesContent":["import {expect} from 'chai';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport validatorFactory from './sortFields';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen';\nimport createDebugLogger from 'debug';\n\ngenerateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'sort-fields'],\n useMetadataFile: true,\n recurse: false,\n fixura: {\n reader: READERS.JSON\n },\n mocha: {\n before: () => testValidatorFactory()\n }\n});\nconst debug = createDebugLogger('@natlibfi/marc-record-validators-melinda/sortFields:test');\n\nasync function testValidatorFactory() {\n const validator = await validatorFactory();\n\n expect(validator)\n .to.be.an('object')\n .that.has.any.keys('description', 'validate');\n\n expect(validator.description).to.be.a('string');\n expect(validator.validate).to.be.a('function');\n}\n\nasync function callback({getFixture, enabled = true, fix = true}) {\n if (enabled === false) {\n debug('TEST SKIPPED!');\n return;\n }\n\n const validator = await validatorFactory();\n const record = new MarcRecord(getFixture('input.json'));\n const expectedResult = getFixture('result.json');\n // console.log(expectedResult); // eslint-disable-line\n\n if (!fix) {\n const result = await validator.validate(record);\n expect(result).to.eql(expectedResult);\n return;\n }\n\n await validator.fix(record);\n expect(record).to.eql(expectedResult);\n}\n"],"mappings":";;AAAA,IAAAA,KAAA,GAAAC,OAAA;AACA,IAAAC,WAAA,GAAAD,OAAA;AACA,IAAAE,WAAA,GAAAC,sBAAA,CAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,QAAA,GAAAF,sBAAA,CAAAH,OAAA;AACA,IAAAM,MAAA,GAAAH,sBAAA,CAAAH,OAAA;AAAsC,SAAAG,uBAAAI,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEtC,IAAAG,gBAAa,EAAC;EACZC,QAAQ;EACRC,IAAI,EAAE,CAACC,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,aAAa,CAAC;EACvDC,eAAe,EAAE,IAAI;EACrBC,OAAO,EAAE,KAAK;EACdC,MAAM,EAAE;IACNC,MAAM,EAAEC,eAAO,CAACC;EAClB,CAAC;EACDC,KAAK,EAAE;IACLC,MAAM,EAAEA,CAAA,KAAMC,oBAAoB,CAAC;EACrC;AACF,CAAC,CAAC;AACF,MAAMC,KAAK,GAAG,IAAAC,cAAiB,EAAC,0DAA0D,CAAC;AAE3F,eAAeF,oBAAoBA,CAAA,EAAG;EACpC,MAAMG,SAAS,GAAG,MAAM,IAAAC,mBAAgB,EAAC,CAAC;EAE1C,IAAAC,YAAM,EAACF,SAAS,CAAC,CACdG,EAAE,CAACC,EAAE,CAACC,EAAE,CAAC,QAAQ,CAAC,CAClBC,IAAI,CAACC,GAAG,CAACC,GAAG,CAACC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC;EAE/C,IAAAP,YAAM,EAACF,SAAS,CAACU,WAAW,CAAC,CAACP,EAAE,CAACC,EAAE,CAACO,CAAC,CAAC,QAAQ,CAAC;EAC/C,IAAAT,YAAM,EAACF,SAAS,CAACY,QAAQ,CAAC,CAACT,EAAE,CAACC,EAAE,CAACO,CAAC,CAAC,UAAU,CAAC;AAChD;AAEA,eAAezB,QAAQA,CAAC;EAAC2B,UAAU;EAAEC,OAAO,GAAG,IAAI;EAAEC,GAAG,GAAG;AAAI,CAAC,EAAE;EAChE,IAAID,OAAO,KAAK,KAAK,EAAE;IACrBhB,KAAK,CAAC,eAAe,CAAC;IACtB;EACF;EAEA,MAAME,SAAS,GAAG,MAAM,IAAAC,mBAAgB,EAAC,CAAC;EAC1C,MAAMe,MAAM,GAAG,IAAIC,sBAAU,CAACJ,UAAU,CAAC,YAAY,CAAC,CAAC;EACvD,MAAMK,cAAc,GAAGL,UAAU,CAAC,aAAa,CAAC;EAChD;;EAEA,IAAI,CAACE,GAAG,EAAE;IACR,MAAMI,MAAM,GAAG,MAAMnB,SAAS,CAACY,QAAQ,CAACI,MAAM,CAAC;IAC/C,IAAAd,YAAM,EAACiB,MAAM,CAAC,CAAChB,EAAE,CAACiB,GAAG,CAACF,cAAc,CAAC;IACrC;EACF;EAEA,MAAMlB,SAAS,CAACe,GAAG,CAACC,MAAM,CAAC;EAC3B,IAAAd,YAAM,EAACc,MAAM,CAAC,CAACb,EAAE,CAACiB,GAAG,CAACF,cAAc,CAAC;AACvC"}
@@ -8,6 +8,7 @@ exports.sortAdjacentESubfields = sortAdjacentESubfields;
8
8
  var _clone = _interopRequireDefault(require("clone"));
9
9
  var _utils = require("./utils");
10
10
  var _punctuation = require("./punctuation2");
11
+ var _sortFields = require("./sortFields");
11
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
13
  // Validator/fixer for sorting $e relator term subfields
13
14
  //
@@ -18,33 +19,10 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
18
19
  //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortRelatorTerms');
19
20
  //const debugData = debug.extend('data');
20
21
  const WORST_WORK = 98;
21
- const relatorTermValues = {
22
- // The higher, the better
23
- // More abstract, the earlier it appears.
24
- // Note that terms with same abstraction level might also have order preferences
25
- // work/teos > expression/ekspressio > manifestation/manifestaatio
26
- 'säveltäjä': 100,
27
- 'kirjoittaja': 99,
28
- // Viola wants composer/säveltäjä on top (highly unlikely to ever appear together, but...)
29
- 'taiteilija': 98,
30
- 'sanoittaja': 90,
31
- // ekspressio
32
- 'sovittaja': 80,
33
- 'toimittaja': 80,
34
- 'kuvittaja': 75,
35
- 'editointi': 71,
36
- 'kääntäjä': 70,
37
- 'lukija': 61,
38
- // manifestaatio
39
- 'esittäjä': 60,
40
- 'johtaja': 50,
41
- 'kustantaja': 41,
42
- 'julkaisija': 40
43
- };
44
22
  function scoreRelatorTerm(term) {
45
23
  const normalizedTerm = normalizeValue(term);
46
- if (normalizedTerm in relatorTermValues) {
47
- return relatorTermValues[normalizedTerm];
24
+ if (normalizedTerm in _sortFields.relatorTermScore) {
25
+ return _sortFields.relatorTermScore[normalizedTerm];
48
26
  }
49
27
  return 0;
50
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sortRelatorTerms.js","names":["_clone","_interopRequireDefault","require","_utils","_punctuation","obj","__esModule","default","WORST_WORK","relatorTermValues","scoreRelatorTerm","term","normalizedTerm","normalizeValue","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","sortAdjacentESubfields","clonedField","clone","clonedFieldAsString","fieldToString","fieldAsString","push","length","value","replace","swapESubfields","subfields","loopAgain","some","sf","index","code","currScore","prevSubfield","prevScore","tmp","fieldFixPunctuation"],"sources":["../src/sortRelatorTerms.js"],"sourcesContent":["// Validator/fixer for sorting $e relator term subfields\n//\n// Author(s): Nicholas Volk\n\nimport clone from 'clone';\n//import createDebugLogger from 'debug';\nimport {fieldToString} from './utils';\nimport {fieldFixPunctuation} from './punctuation2';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortRelatorTerms');\n//const debugData = debug.extend('data');\n\nconst WORST_WORK = 98;\n\nconst relatorTermValues = { // The higher, the better\n // More abstract, the earlier it appears.\n // Note that terms with same abstraction level might also have order preferences\n // work/teos > expression/ekspressio > manifestation/manifestaatio\n 'säveltäjä': 100,\n 'kirjoittaja': 99, // Viola wants composer/säveltäjä on top (highly unlikely to ever appear together, but...)\n 'taiteilija': 98,\n 'sanoittaja': 90,\n // ekspressio\n 'sovittaja': 80,\n 'toimittaja': 80,\n 'kuvittaja': 75,\n 'editointi': 71,\n 'kääntäjä': 70,\n 'lukija': 61,\n // manifestaatio\n 'esittäjä': 60,\n 'johtaja': 50,\n 'kustantaja': 41,\n 'julkaisija': 40\n\n};\n\nfunction scoreRelatorTerm(term) {\n const normalizedTerm = normalizeValue(term);\n if (normalizedTerm in relatorTermValues) {\n return relatorTermValues[normalizedTerm];\n }\n return 0;\n}\n\nexport default function () {\n\n return {\n description: 'Sort adjacent $e subfields in field [1678][01]0',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n record.fields.forEach(field => {\n sortAdjacentESubfields(field);\n });\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n record.fields.forEach(field => {\n const clonedField = clone(field);\n sortAdjacentESubfields(clonedField);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) { // eslint-disable-line functional/no-conditional-statements\n res.message.push(`${fieldAsString} => ${clonedFieldAsString}`); // eslint-disable-line functional/immutable-data\n }\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\n\nfunction normalizeValue(value) {\n // Removing last punc char is good enough for our purposes.\n // We don't handle abbreviations here etc.\n // Brackets should not happen either, should they?\n return value.replace(/[.,]$/u, '');\n}\n\n\nfunction swapESubfields(field) {\n if (!field.subfields) {\n return;\n }\n\n const loopAgain = field.subfields.some((sf, index) => {\n if (index === 0 || sf.code !== 'e') {\n return false;\n }\n const currScore = scoreRelatorTerm(sf.value);\n\n const prevSubfield = field.subfields[index - 1];\n if (currScore === 0 || prevSubfield.code !== 'e') {\n return false;\n }\n const prevScore = scoreRelatorTerm(prevSubfield.value);\n\n\n // If this subfield maps to a Work, then subfields can be swapped, even if we don't have a score for the prev subfield!\n if (prevScore === 0 && currScore < WORST_WORK) {\n return false;\n }\n\n if (currScore > prevScore) {\n // Swap:\n const tmp = field.subfields[index - 1];\n field.subfields[index - 1] = sf; // eslint-disable-line functional/immutable-data\n field.subfields[index] = tmp; // eslint-disable-line functional/immutable-data\n fieldFixPunctuation(field);\n return true;\n }\n\n return false;\n\n });\n\n if (loopAgain) {\n swapESubfields(field); // uh, evil recursion...\n return;\n }\n\n return;\n\n}\n\nexport function sortAdjacentESubfields(field) {\n if (!field.subfields) {\n return field;\n }\n swapESubfields(field);\n\n return field;\n}\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"sortRelatorTerms.js","names":["_clone","_interopRequireDefault","require","_utils","_punctuation","_sortFields","obj","__esModule","default","WORST_WORK","scoreRelatorTerm","term","normalizedTerm","normalizeValue","relatorTermScore","_default","description","validate","fix","record","res","message","valid","fields","forEach","field","sortAdjacentESubfields","clonedField","clone","clonedFieldAsString","fieldToString","fieldAsString","push","length","value","replace","swapESubfields","subfields","loopAgain","some","sf","index","code","currScore","prevSubfield","prevScore","tmp","fieldFixPunctuation"],"sources":["../src/sortRelatorTerms.js"],"sourcesContent":["// Validator/fixer for sorting $e relator term subfields\n//\n// Author(s): Nicholas Volk\n\nimport clone from 'clone';\n//import createDebugLogger from 'debug';\nimport {fieldToString} from './utils';\nimport {fieldFixPunctuation} from './punctuation2';\nimport {relatorTermScore} from './sortFields';\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortRelatorTerms');\n//const debugData = debug.extend('data');\n\nconst WORST_WORK = 98;\n\nfunction scoreRelatorTerm(term) {\n const normalizedTerm = normalizeValue(term);\n if (normalizedTerm in relatorTermScore) {\n return relatorTermScore[normalizedTerm];\n }\n return 0;\n}\n\nexport default function () {\n\n return {\n description: 'Sort adjacent $e subfields in field [1678][01]0',\n validate, fix\n };\n\n function fix(record) {\n const res = {message: [], fix: [], valid: true};\n\n record.fields.forEach(field => {\n sortAdjacentESubfields(field);\n });\n\n return res;\n }\n\n function validate(record) {\n const res = {message: []};\n\n record.fields.forEach(field => {\n const clonedField = clone(field);\n sortAdjacentESubfields(clonedField);\n const clonedFieldAsString = fieldToString(clonedField);\n const fieldAsString = fieldToString(field);\n if (fieldAsString !== clonedFieldAsString) { // eslint-disable-line functional/no-conditional-statements\n res.message.push(`${fieldAsString} => ${clonedFieldAsString}`); // eslint-disable-line functional/immutable-data\n }\n });\n\n res.valid = !(res.message.length >= 1); // eslint-disable-line functional/immutable-data\n return res;\n }\n}\n\n\nfunction normalizeValue(value) {\n // Removing last punc char is good enough for our purposes.\n // We don't handle abbreviations here etc.\n // Brackets should not happen either, should they?\n return value.replace(/[.,]$/u, '');\n}\n\n\nfunction swapESubfields(field) {\n if (!field.subfields) {\n return;\n }\n\n const loopAgain = field.subfields.some((sf, index) => {\n if (index === 0 || sf.code !== 'e') {\n return false;\n }\n const currScore = scoreRelatorTerm(sf.value);\n\n const prevSubfield = field.subfields[index - 1];\n if (currScore === 0 || prevSubfield.code !== 'e') {\n return false;\n }\n const prevScore = scoreRelatorTerm(prevSubfield.value);\n\n\n // If this subfield maps to a Work, then subfields can be swapped, even if we don't have a score for the prev subfield!\n if (prevScore === 0 && currScore < WORST_WORK) {\n return false;\n }\n\n if (currScore > prevScore) {\n // Swap:\n const tmp = field.subfields[index - 1];\n field.subfields[index - 1] = sf; // eslint-disable-line functional/immutable-data\n field.subfields[index] = tmp; // eslint-disable-line functional/immutable-data\n fieldFixPunctuation(field);\n return true;\n }\n\n return false;\n\n });\n\n if (loopAgain) {\n swapESubfields(field); // uh, evil recursion...\n return;\n }\n\n return;\n\n}\n\nexport function sortAdjacentESubfields(field) {\n if (!field.subfields) {\n return field;\n }\n swapESubfields(field);\n\n return field;\n}\n\n"],"mappings":"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"}
@@ -18,19 +18,28 @@ const defaultSortOrderStringFinns = '8673abcdefghijklmnopqrstuvwxyz420159'; // N
18
18
  const defaultSortOrderStringOthers = '8673abcdefghijklmnopqrstuvwxyz402159';
19
19
  const defaultSortOrderFinns = defaultSortOrderStringFinns.split('');
20
20
  const defaultSortOrderOthers = defaultSortOrderStringOthers.split('');
21
- function _default() {
21
+ function _default(tagPattern) {
22
22
  return {
23
23
  description: 'Swap adjacent subfields',
24
24
  validate,
25
25
  fix
26
26
  };
27
- function fix(record) {
27
+ function getRelevantFields(record, tagPattern) {
28
+ const datafields = record.fields.filter(f => f.subfields);
29
+ if (!tagPattern) {
30
+ return datafields;
31
+ }
32
+ const regexp = new RegExp(tagPattern, 'u');
33
+ return datafields.filter(f => regexp.test(f.tag));
34
+ }
35
+ function fix(record, tagPattern) {
28
36
  const res = {
29
37
  message: [],
30
38
  fix: [],
31
39
  valid: true
32
40
  };
33
- record.fields.forEach(field => {
41
+ const relevantFields = getRelevantFields(record, tagPattern);
42
+ relevantFields.forEach(field => {
34
43
  sortAdjacentSubfields(field);
35
44
  });
36
45
  return res;
@@ -39,7 +48,8 @@ function _default() {
39
48
  const res = {
40
49
  message: []
41
50
  };
42
- record.fields.forEach(field => {
51
+ const relevantFields = getRelevantFields(record, tagPattern);
52
+ relevantFields.forEach(field => {
43
53
  const clonedField = (0, _clone.default)(field);
44
54
  sortAdjacentSubfields(clonedField);
45
55
  const clonedFieldAsString = (0, _utils.fieldToString)(clonedField);