@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.
- package/dist/access-rights.spec.js +2 -2
- package/dist/access-rights.spec.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/normalize-dashes.js +70 -0
- package/dist/normalize-dashes.js.map +1 -0
- package/dist/normalize-dashes.spec.js +51 -0
- package/dist/normalize-dashes.spec.js.map +1 -0
- package/dist/resolvable-ext-references-melinda.spec.js +2 -2
- package/dist/resolvable-ext-references-melinda.spec.js.map +1 -1
- package/dist/sortFields.js +182 -263
- package/dist/sortFields.js.map +1 -1
- package/package.json +3 -3
- package/src/access-rights.spec.js +2 -2
- package/src/index.js +2 -0
- package/src/normalize-dashes.js +69 -0
- package/src/normalize-dashes.spec.js +52 -0
- package/src/sortFields.js +169 -258
- package/test-fixtures/normalize-dashes/01/expectedResult.json +6 -0
- package/test-fixtures/normalize-dashes/01/metadata.json +6 -0
- package/test-fixtures/normalize-dashes/01/record.json +8 -0
- package/test-fixtures/normalize-dashes/02/expectedResult.json +10 -0
- package/test-fixtures/normalize-dashes/02/metadata.json +5 -0
- package/test-fixtures/normalize-dashes/02/record.json +8 -0
- package/test-fixtures/normalize-dashes/03/expectedResult.json +5 -0
- package/test-fixtures/normalize-dashes/03/metadata.json +5 -0
- package/test-fixtures/normalize-dashes/03/record.json +9 -0
package/dist/sortFields.js
CHANGED
|
@@ -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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
293
|
-
|
|
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
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
|
310
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
380
|
-
return
|
|
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
|
package/dist/sortFields.js.map
CHANGED
|
@@ -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.
|
|
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": "^
|
|
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.
|
|
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,
|
|
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,
|
|
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,
|