@natlibfi/marc-record-validators-melinda 10.14.0 → 10.15.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.
@@ -8,20 +8,22 @@ exports.fieldOrderComparator = fieldOrderComparator;
8
8
  exports.relatorTermScore = void 0;
9
9
  exports.scoreRelatorTerm = scoreRelatorTerm;
10
10
  var _clone = _interopRequireDefault(require("clone"));
11
- var _debug = _interopRequireDefault(require("debug"));
12
11
  var _utils = require("./utils");
12
+ var _marcFieldSort = require("@natlibfi/marc-record/dist/marcFieldSort");
13
13
  var _subfield8Utils = require("./subfield8Utils");
14
14
  var _subfield6Utils = require("./subfield6Utils");
15
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
16
  // Taken from project marc-record-js, file marcSortFields.js as this contains more and more Melinda-specific rules.
17
17
 
18
- const BIG_BAD_NUMBER = 999.99;
19
- const debug = (0, _debug.default)('@natlibfi/marc-record-validators-melinda:sortFields');
18
+ //import createDebugLogger from 'debug';
19
+
20
+ //const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortFields');
20
21
  //const debugData = debug.extend('data');
21
- const debugDev = debug.extend('dev');
22
+ //const debugDev = debug.extend('dev');
23
+ const BIG_BAD_NUMBER = 999999999;
22
24
  function _default() {
23
25
  return {
24
- description: 'Sort fields',
26
+ description: 'Sort fields using both generic and Melinda specific rules',
25
27
  validate,
26
28
  fix
27
29
  };
@@ -93,291 +95,208 @@ function scoreRelatorTerm(value) {
93
95
  return 0;
94
96
  }
95
97
  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
98
+ //const sorterFunctions = [sortByTag, sortByIndexTerms, sortAlphabetically, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];
138
99
 
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
- }
100
+ const sorterFunctions = [_marcFieldSort.sortByTag, sortByIndexTerms, _marcFieldSort.sortAlphabetically, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];
101
+ //const sorterFunctions = [sortByIndexTerms, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];
156
102
 
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
- }
103
+ return (0, _marcFieldSort.fieldOrderComparator)(fieldA, fieldB, sorterFunctions);
104
+ }
105
+ function sortByIndexTerms(fieldA, fieldB) {
106
+ // eslint-disable-line complexity, max-statements
166
107
 
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;
108
+ const indexTermFields = ['600', '610', '611', '630', '648', '650', '651', '652', '653', '654', '655', '656', '657', '658', '659', '662'];
109
+ function scoreInd2(val) {
110
+ const ind2Score = {
111
+ '0': 0,
112
+ '1': 1,
113
+ '2': 2,
114
+ '3': 3,
115
+ '4': 8,
116
+ '5': 5,
117
+ '6': 6,
118
+ '7': 7
119
+ };
120
+ if (val in ind2Score) {
121
+ return ind2Score[val];
209
122
  }
210
- //}
123
+ return 9;
124
+ }
125
+
126
+ // ATM this is not needed.
127
+ // You may need this, if you change compare function order in sorterFunctions
128
+ // istanbul ignore next
129
+ if (fieldA.tag !== fieldB.tag) {
211
130
  return 0;
212
131
  }
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
- }
132
+ if (!indexTermFields.includes(fieldA.tag)) {
222
133
  return 0;
223
134
  }
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');
135
+
136
+ // Puts ind2=4 last
137
+ if (scoreInd2(fieldA.ind2) > scoreInd2(fieldB.ind2)) {
138
+ return 1;
234
139
  }
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;
140
+ if (scoreInd2(fieldA.ind2) < scoreInd2(fieldB.ind2)) {
141
+ return -1;
142
+ }
143
+ function scoreDictionary(dictionary) {
144
+ const dictionarySortIndex = {
145
+ 'yso/fin': 0,
146
+ 'yso/swe': 1,
147
+ 'yso/eng': 2,
148
+ 'slm/fin': 0.1,
149
+ 'slm/swe': 1.1,
150
+ 'kauno/fin': 2.1,
151
+ 'kauno/swe': 2.2,
152
+ 'kaunokki': 4,
153
+ 'bella': 5
154
+ };
155
+ if (dictionary in dictionarySortIndex) {
156
+ return dictionarySortIndex[dictionary];
256
157
  }
158
+ return BIG_BAD_NUMBER;
159
+ }
160
+ const dictionaryA = selectFirstValue(fieldA, '2');
161
+ const dictionaryB = selectFirstValue(fieldB, '2');
162
+ const dictScoreA = scoreDictionary(dictionaryA);
163
+ const dictScoreB = scoreDictionary(dictionaryB);
164
+ // Use priority order for listed dictionaries:
165
+ if (dictScoreA > dictScoreB) {
166
+ return 1;
167
+ }
168
+ if (dictScoreA < dictScoreB) {
169
+ return -1;
170
+ }
171
+ // Unlisted dictionaries: sort $2 value alphabetically:
172
+ //if (dictScoreA === BIG_BAD_NUMBER) {
173
+ if (dictionaryA > dictionaryB) {
174
+ return 1;
175
+ }
176
+ if (dictionaryA < dictionaryB) {
177
+ return -1;
178
+ }
179
+ //}
180
+ return 0;
181
+ }
182
+ function preferKeep(fieldA, fieldB, keepOwner = 'FENNI') {
183
+ const hasKeepA = (0, _utils.fieldHasSubfield)(fieldA, '9', `${keepOwner}<KEEP>`);
184
+ const hasKeepB = (0, _utils.fieldHasSubfield)(fieldB, '9', `${keepOwner}<KEEP>`);
185
+ if (hasKeepA && !hasKeepB) {
186
+ return -1;
187
+ }
188
+ if (!hasKeepA && hasKeepB) {
189
+ return 1;
190
+ }
191
+ return 0;
192
+ }
193
+ function preferFenniKeep(fieldA, fieldB) {
194
+ const fenniPreference = preferKeep(fieldA, fieldB, 'FENNI');
195
+ if (fenniPreference !== 0) {
196
+ return fenniPreference;
197
+ }
198
+ const violaPreference = preferKeep(fieldA, fieldB, 'VIOLA');
199
+ if (violaPreference !== 0) {
200
+ return violaPreference;
201
+ }
202
+ return preferKeep(fieldA, fieldB, 'FIKKA');
203
+ }
204
+ function sortByRelatorTerm(fieldA, fieldB) {
205
+ // Should this be done to 6XX and 8XX fields as well? Does $t affect sorting?
206
+ if (!['700', '710', '711', '730'].includes(fieldA.tag)) {
257
207
  return 0;
258
208
  }
259
- function fieldGetMinLinkAndSequenceNumber(field) {
209
+ function fieldGetMaxRelatorTermScore(field) {
260
210
  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
211
  return 0;
279
212
  }
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
- }
213
+ const e = field.subfields.filter(sf => sf.code === 'e');
214
+ const scores = e.map(sf => scoreRelatorTerm(sf.value));
215
+ //debugDev(`RELATOR SCORE FOR '${fieldToString(field)}': ${scores.join(', ')}`);
216
+ return Math.max(...scores);
217
+ }
218
+ const scoreA = fieldGetMaxRelatorTermScore(fieldA);
219
+ const scoreB = fieldGetMaxRelatorTermScore(fieldB);
220
+ if (scoreA < scoreB) {
221
+ return 1;
222
+ }
223
+ if (scoreA > scoreB) {
290
224
  return -1;
291
225
  }
292
- function sortByOccurrenceNumber(fieldA, fieldB) {
293
- // Sort by subfield $6
226
+ return 0;
227
+ }
228
+ function fieldGetMinLinkAndSequenceNumber(field) {
229
+ if (!field.subfields) {
230
+ return BIG_BAD_NUMBER;
231
+ }
232
+ const relevantSubfields = field.subfields.filter(sf => (0, _subfield8Utils.isValidSubfield8)(sf));
233
+ // 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:
234
+ const scores = relevantSubfields.map(sf => parseFloat(sf.value.replace(/\\.*$/u, '')));
235
+ if (scores.length === 0) {
236
+ return BIG_BAD_NUMBER;
237
+ }
238
+ return Math.min(...scores);
239
+ }
240
+ function sortByFieldLinkAndSequenceNumber(fieldA, fieldB) {
241
+ // Sort by subfield $8 that is...
242
+ const scoreA = fieldGetMinLinkAndSequenceNumber(fieldA);
243
+ const scoreB = fieldGetMinLinkAndSequenceNumber(fieldB);
244
+ //debugDev(` sf-8-A-score for '${fieldToString(fieldA)}: ${scoreA}`);
245
+ //debugDev(` sf-8-B-score for '${fieldToString(fieldB)}: ${scoreB}`);
246
+ if (scoreA === scoreB) {
247
+ return 0;
248
+ }
249
+ if (scoreB === 0) {
250
+ return 1;
251
+ }
252
+ if (scoreA === 0) {
253
+ return -1;
254
+ }
255
+ if (scoreA > scoreB) {
256
+ // smaller is better
257
+ return 1;
258
+ }
259
+ return -1;
260
+ }
261
+ function sortByOccurrenceNumber(fieldA, fieldB) {
262
+ // Sort by subfield $6
294
263
 
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') {
264
+ function fieldGetOccurrenceNumber(field) {
265
+ // should this function be exported? (based on validator sortRelatorFields.js)
266
+ if (!field.subfields) {
307
267
  return 0;
308
268
  }
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) {
269
+ const subfield6 = field.subfields.find(sf => (0, _subfield6Utils.isValidSubfield6)(sf));
270
+ if (subfield6 === undefined) {
316
271
  return 0;
317
272
  }
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;
273
+ return parseInt((0, _subfield6Utils.subfield6GetOccurrenceNumber)(subfield6), 10);
329
274
  }
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
- }
275
+ if (fieldA.tag !== '880') {
374
276
  return 0;
375
277
  }
278
+ const scoreA = fieldGetOccurrenceNumber(fieldA);
279
+ const scoreB = fieldGetOccurrenceNumber(fieldB);
376
280
 
377
- //-----------------------------------------------------------------------------
281
+ //debugDev(`A: '${fieldToString(fieldA)}: ${scoreA}`);
282
+ //debugDev(`B: '${fieldToString(fieldB)}: ${scoreB}`);
378
283
 
379
- function selectFirstValue(field, subcode) {
380
- return field.subfields.filter(subfield => subcode === subfield.code).map(subfield => subfield.value).slice(0, 1);
284
+ if (scoreA === scoreB) {
285
+ return 0;
381
286
  }
287
+ if (scoreB === 0) {
288
+ return -1;
289
+ }
290
+ if (scoreA === 0) {
291
+ return 1;
292
+ }
293
+ if (scoreA > scoreB) {
294
+ // smaller is better
295
+ return 1;
296
+ }
297
+ return -1;
298
+ }
299
+ function selectFirstValue(field, subcode) {
300
+ return field.subfields.filter(subfield => subcode === subfield.code).map(subfield => subfield.value).slice(0, 1);
382
301
  }
383
302
  //# sourceMappingURL=sortFields.js.map
@@ -1 +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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"}
1
+ {"version":3,"file":"sortFields.js","names":["_clone","_interopRequireDefault","require","_utils","_marcFieldSort","_subfield8Utils","_subfield6Utils","obj","__esModule","default","BIG_BAD_NUMBER","_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","globalFieldOrderComparator","indexTermFields","scoreInd2","val","ind2Score","tag","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","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';\n//import createDebugLogger from 'debug';\nimport {fieldHasSubfield, fieldToString} from './utils';\nimport {sortByTag, sortAlphabetically, fieldOrderComparator as globalFieldOrderComparator} from '@natlibfi/marc-record/dist/marcFieldSort';\nimport {isValidSubfield8} from './subfield8Utils';\nimport {isValidSubfield6, subfield6GetOccurrenceNumber} from './subfield6Utils';\n\n//const debug = createDebugLogger('@natlibfi/marc-record-validators-melinda:sortFields');\n//const debugData = debug.extend('data');\n//const debugDev = debug.extend('dev');\n\nconst BIG_BAD_NUMBER = 999999999;\nexport default function () {\n\n return {\n description: 'Sort fields using both generic and Melinda specific rules',\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 const sorterFunctions = [sortByTag, sortByIndexTerms, sortAlphabetically, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];\n //const sorterFunctions = [sortByIndexTerms, sortByRelatorTerm, sortByOccurrenceNumber, preferFenniKeep, sortByFieldLinkAndSequenceNumber];\n\n return globalFieldOrderComparator(fieldA, fieldB, sorterFunctions);\n}\n\nfunction 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\nfunction 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\nfunction 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\nfunction 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 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\nfunction 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\nfunction 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\nfunction 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\nfunction 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"],"mappings":"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"}
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "url": "git@github.com:natlibfi/marc-record-validators-melinda.git"
15
15
  },
16
16
  "license": "MIT",
17
- "version": "10.14.0",
17
+ "version": "10.15.0-alpha.1",
18
18
  "main": "./dist/index.js",
19
19
  "publishConfig": {
20
20
  "access": "public"
@@ -37,12 +37,12 @@
37
37
  "dependencies": {
38
38
  "@babel/register": "^7.22.15",
39
39
  "@natlibfi/issn-verify": "^1.0.3",
40
- "@natlibfi/marc-record": "^7.3.1",
40
+ "@natlibfi/marc-record": "^8.0.0-alpha.1",
41
41
  "@natlibfi/marc-record-validate": "^8.0.1",
42
42
  "cld3-asm": "^3.1.1",
43
43
  "clone": "^2.1.2",
44
44
  "debug": "^4.3.4",
45
- "isbn3": "^1.1.41",
45
+ "isbn3": "^1.1.42",
46
46
  "langs": "^2.0.0",
47
47
  "node-fetch": "^2.7.0",
48
48
  "xml2js": "^0.6.2"
@@ -116,11 +116,11 @@ describe('access-rights', async () => {
116
116
  });
117
117
 
118
118
  it('5061 but missing 540; Adds 540', async () => {
119
- await test.fix([ldf5061, f540], [ldf5061, ldf540, f540]);
119
+ await test.fix([ldf5061, f540], [ldf5061, f540, ldf540]);
120
120
  });
121
121
 
122
122
  it('Both, 5061 and 540, missing; Adds 5061 and 540', async () => {
123
- await test.fix([f5060, f540], [f5060, ldf5061, ldf540, f540]);
123
+ await test.fix([f5060, f540], [f5060, ldf5061, f540, ldf540]);
124
124
  });
125
125
  });
126
126
  });
package/src/index.js CHANGED
@@ -19,6 +19,7 @@ import MergeField500Lisapainokset from './mergeField500Lisapainokset';
19
19
  import MergeRelatorTermFields from './mergeRelatorTermFields';
20
20
  import MultipleSubfield0s from './multiple-subfield-0';
21
21
  import NonBreakingSpace from './non-breaking-space';
22
+ import NormalizeDashes from './normalize-dashes';
22
23
  import NormalizeIdentifiers from './normalize-identifiers';
23
24
  import NormalizeQualifyingInformation from './normalize-qualifying-information';
24
25
  import NormalizeUTF8Diacritics from './normalize-utf8-diacritics';
@@ -65,6 +66,7 @@ export {
65
66
  MergeRelatorTermFields,
66
67
  MultipleSubfield0s,
67
68
  NonBreakingSpace,
69
+ NormalizeDashes,
68
70
  NormalizeIdentifiers,
69
71
  NormalizeQualifyingInformation,
70
72
  NormalizeUTF8Diacritics,