@natlibfi/marc-record-validators-melinda 9.0.4 → 9.0.6
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/isbn-issn.js +199 -83
- package/dist/isbn-issn.js.map +1 -1
- package/dist/isbn-issn.spec.js +191 -20
- package/dist/isbn-issn.spec.js.map +1 -1
- package/package.json +1 -1
- package/src/isbn-issn.js +168 -72
- package/src/isbn-issn.spec.js +93 -26
package/dist/isbn-issn.js
CHANGED
|
@@ -17,7 +17,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
17
17
|
*
|
|
18
18
|
* MARC record validators used in Melinda
|
|
19
19
|
*
|
|
20
|
-
* Copyright (c) 2014-
|
|
20
|
+
* Copyright (c) 2014-2022 University Of Helsinki (The National Library Of Finland)
|
|
21
21
|
*
|
|
22
22
|
* This file is part of marc-record-validators-melinda
|
|
23
23
|
*
|
|
@@ -38,6 +38,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
38
38
|
* for the JavaScript code in this file.
|
|
39
39
|
*
|
|
40
40
|
*/
|
|
41
|
+
// handleInvalid: move invalid 020$a to 020$z, and invalid 022$a to 022$y
|
|
41
42
|
var _default = ({
|
|
42
43
|
hyphenateISBN = false,
|
|
43
44
|
handleInvalid = false
|
|
@@ -48,62 +49,118 @@ var _default = ({
|
|
|
48
49
|
description: 'Validates ISBN and ISSN values'
|
|
49
50
|
};
|
|
50
51
|
|
|
51
|
-
function
|
|
52
|
-
return
|
|
53
|
-
|
|
54
|
-
// Check ISBN:
|
|
55
|
-
if (field.tag === '020') {
|
|
56
|
-
if (invalidField020(field)) {
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
52
|
+
function stringHasSpace(str) {
|
|
53
|
+
return str.indexOf(' ') > -1;
|
|
54
|
+
}
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
function trimSpaces(value) {
|
|
57
|
+
return value.replace(/^\s+/u, '').replace(/\s+$/u, '').replace(/\s+/gu, ' ');
|
|
58
|
+
}
|
|
61
59
|
|
|
62
|
-
|
|
60
|
+
function isMultiWord(inputString) {
|
|
61
|
+
const trimmedString = trimSpaces(inputString);
|
|
62
|
+
return stringHasSpace(trimmedString);
|
|
63
|
+
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
function getFirstWord(inputString) {
|
|
66
|
+
const trimmedString = trimSpaces(inputString);
|
|
67
|
+
const arr = trimmedString.split(' ');
|
|
68
|
+
return arr[0];
|
|
69
|
+
}
|
|
68
70
|
|
|
71
|
+
function invalidISBN(isbn) {
|
|
72
|
+
const isbnOnly = getFirstWord(isbn);
|
|
69
73
|
|
|
70
|
-
|
|
74
|
+
const auditedIsbn = _isbn.default.audit(isbnOnly);
|
|
71
75
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
76
|
+
return !auditedIsbn.validIsbn;
|
|
77
|
+
}
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
function invalidSubfield(subfield) {
|
|
80
|
+
if (subfield.code !== 'a') {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
78
83
|
|
|
84
|
+
return invalidISBN(subfield.value) || isMultiWord(subfield.value);
|
|
85
|
+
}
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
function invalidField020(field) {
|
|
88
|
+
if (field.subfields && field.subfields.some(sf => invalidSubfield(sf))) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function subfieldsIsbnRequiresHyphenation(subfield) {
|
|
96
|
+
if (!hyphenateISBN || !['a', 'z'].includes(subfield.code)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const isbn = getFirstWord(subfield.value);
|
|
101
|
+
|
|
102
|
+
if (subfield.code === 'a') {
|
|
103
|
+
return requiresHyphenation(isbn);
|
|
104
|
+
} // $z is a bit hacky: hyphenation is required only iff valid and no '-' chars
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
if (isbn.indexOf('-') > -1) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return !invalidISBN(isbn);
|
|
112
|
+
|
|
113
|
+
function requiresHyphenation(isbn) {
|
|
114
|
+
if (!hyphenateISBN) {
|
|
115
|
+
return false;
|
|
116
|
+
} // Handle old notation such as "978-952-396-001-5 (nid.)"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
const isbn2 = getFirstWord(isbn);
|
|
120
|
+
|
|
121
|
+
if (invalidISBN(isbn2)) {
|
|
122
|
+
return false;
|
|
82
123
|
}
|
|
83
124
|
|
|
84
|
-
const
|
|
85
|
-
return !(0, _issnVerify.default)(subfield.value);
|
|
86
|
-
});
|
|
125
|
+
const parsedIsbn = _isbn.default.parse(isbn2); // Return true only if existing ISBN is a valid and hyphenated 10 or 13 digit ISBN:
|
|
87
126
|
|
|
88
|
-
function invalidField020(field) {
|
|
89
|
-
const subfieldA = field.subfields.find(sf => sf.code === 'a');
|
|
90
127
|
|
|
91
|
-
|
|
92
|
-
|
|
128
|
+
return !(isbn2 === parsedIsbn.isbn10h || isbn2 === parsedIsbn.isbn13h);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
93
131
|
|
|
94
|
-
|
|
95
|
-
|
|
132
|
+
function getRelevantFields(record) {
|
|
133
|
+
//return record.get(/^(?:020|022)$/u).filter(field => {
|
|
134
|
+
return record.fields.filter(field => {
|
|
135
|
+
if (!field.subfields) {
|
|
136
|
+
return false;
|
|
137
|
+
} // Check ISBN:
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if (field.tag === '020') {
|
|
141
|
+
if (invalidField020(field)) {
|
|
142
|
+
// checks multiwordness
|
|
143
|
+
return true;
|
|
96
144
|
}
|
|
97
145
|
|
|
98
|
-
return
|
|
99
|
-
} //
|
|
146
|
+
return fieldsIsbnRequiresHyphenation(field);
|
|
147
|
+
} // Check ISSN:
|
|
100
148
|
|
|
101
149
|
|
|
102
|
-
if (
|
|
103
|
-
|
|
150
|
+
if (field.tag === '022') {
|
|
151
|
+
if (invalidField022(field)) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');
|
|
156
|
+
return !(0, _issnVerify.default)(subfield.value);
|
|
104
157
|
}
|
|
105
158
|
|
|
106
159
|
return false;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
function fieldsIsbnRequiresHyphenation(field) {
|
|
163
|
+
return field.subfields && field.subfields.some(sf => subfieldsIsbnRequiresHyphenation(sf));
|
|
107
164
|
}
|
|
108
165
|
|
|
109
166
|
function invalidField022(field) {
|
|
@@ -124,7 +181,7 @@ var _default = ({
|
|
|
124
181
|
}
|
|
125
182
|
|
|
126
183
|
function validate(record) {
|
|
127
|
-
const fields =
|
|
184
|
+
const fields = getRelevantFields(record);
|
|
128
185
|
|
|
129
186
|
if (fields.length === 0) {
|
|
130
187
|
return {
|
|
@@ -143,6 +200,15 @@ var _default = ({
|
|
|
143
200
|
};
|
|
144
201
|
}
|
|
145
202
|
|
|
203
|
+
const subfieldZ = field.subfields.find(sf => sf.code === 'z');
|
|
204
|
+
|
|
205
|
+
if (subfieldZ) {
|
|
206
|
+
return {
|
|
207
|
+
name: 'ISBN (subfield Z)',
|
|
208
|
+
value: subfieldZ.value
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
146
212
|
return {
|
|
147
213
|
name: 'ISBN',
|
|
148
214
|
value: undefined
|
|
@@ -179,68 +245,118 @@ var _default = ({
|
|
|
179
245
|
}
|
|
180
246
|
|
|
181
247
|
function fix(record) {
|
|
182
|
-
|
|
248
|
+
getRelevantFields(record).forEach(field => {
|
|
183
249
|
if (field.tag === '020') {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// ISBN is valid but is missing hyphens
|
|
188
|
-
const normalizedValue = normalizeIsbnValue(subfield.value);
|
|
189
|
-
|
|
190
|
-
if (normalizedValue !== undefined) {
|
|
191
|
-
// eslint-disable-line functional/no-conditional-statement
|
|
192
|
-
subfield.value = normalizedValue; // eslint-disable-line functional/immutable-data
|
|
193
|
-
} else if (handleInvalid) {
|
|
194
|
-
// eslint-disable-line functional/no-conditional-statement
|
|
195
|
-
field.subfields.push({
|
|
196
|
-
code: 'z',
|
|
197
|
-
value: subfield.value
|
|
198
|
-
}); // eslint-disable-line functional/immutable-data
|
|
199
|
-
|
|
200
|
-
record.removeSubfield(subfield, field);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
} else {
|
|
204
|
-
const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');
|
|
250
|
+
field.subfields.forEach(subfield => fixField020Subfield(field, subfield));
|
|
251
|
+
return;
|
|
252
|
+
} // 022 ISSN:
|
|
205
253
|
|
|
206
|
-
if (subfield && handleInvalid) {
|
|
207
|
-
// eslint-disable-line functional/no-conditional-statement
|
|
208
|
-
field.subfields.push({
|
|
209
|
-
code: 'y',
|
|
210
|
-
value: trimSpaces(subfield.value)
|
|
211
|
-
}); // eslint-disable-line functional/immutable-data
|
|
212
254
|
|
|
213
|
-
|
|
214
|
-
|
|
255
|
+
const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');
|
|
256
|
+
|
|
257
|
+
if (subfield && handleInvalid) {
|
|
258
|
+
// eslint-disable-line functional/no-conditional-statement
|
|
259
|
+
// $a/$l => $y (bit overkill to add $z and remove $a/$l instead of just renaming)
|
|
260
|
+
field.subfields.push({
|
|
261
|
+
code: 'y',
|
|
262
|
+
value: subfield.value
|
|
263
|
+
}); // eslint-disable-line functional/immutable-data
|
|
264
|
+
|
|
265
|
+
record.removeSubfield(subfield, field);
|
|
215
266
|
}
|
|
216
267
|
});
|
|
217
268
|
|
|
218
|
-
function
|
|
219
|
-
|
|
269
|
+
function fixField020Subfield(field, subfield) {
|
|
270
|
+
split020A(); // subfield and field are in the scope
|
|
220
271
|
|
|
221
|
-
|
|
272
|
+
addHyphens(subfield);
|
|
273
|
+
handleInvalidIsbn(field, subfield); // remove 020$a, add 020$z, Do this last, as it uses deletion
|
|
222
274
|
|
|
223
|
-
|
|
224
|
-
const parsedIsbn = _isbn.default.parse(trimmedValue);
|
|
275
|
+
return;
|
|
225
276
|
|
|
226
|
-
|
|
277
|
+
function addHyphens(subfield) {
|
|
278
|
+
if (!subfieldsIsbnRequiresHyphenation(subfield)) {
|
|
279
|
+
return;
|
|
280
|
+
} // ISBN is valid but is missing hyphens
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
const normalizedValue = normalizeIsbnValue(subfield.value);
|
|
284
|
+
|
|
285
|
+
if (normalizedValue !== undefined) {
|
|
227
286
|
// eslint-disable-line functional/no-conditional-statement
|
|
228
|
-
|
|
229
|
-
}
|
|
287
|
+
subfield.value = normalizedValue; // eslint-disable-line functional/immutable-data
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function handleInvalidIsbn(field, subfield) {
|
|
292
|
+
if (subfield.code !== 'a' || !handleInvalid) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const head = getFirstWord(subfield.value);
|
|
230
297
|
|
|
298
|
+
if (!invalidISBN(head)) {
|
|
299
|
+
return;
|
|
300
|
+
} // $a => $z (bit overkill to add $z and remove $a instead of just renaming, but too lazy to fix/test thorougly)
|
|
231
301
|
|
|
232
|
-
|
|
302
|
+
|
|
303
|
+
field.subfields.push({
|
|
304
|
+
code: 'z',
|
|
305
|
+
value: subfield.value
|
|
306
|
+
}); // eslint-disable-line functional/immutable-data
|
|
307
|
+
|
|
308
|
+
record.removeSubfield(subfield, field);
|
|
233
309
|
}
|
|
234
310
|
|
|
235
|
-
|
|
236
|
-
|
|
311
|
+
function split020A() {
|
|
312
|
+
// Move non-initial words from $a to $q:
|
|
313
|
+
if (subfield.code !== 'a') {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
237
316
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
317
|
+
const value = trimSpaces(subfield.value);
|
|
318
|
+
const position = value.indexOf(' ');
|
|
319
|
+
|
|
320
|
+
if (position === -1) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const head = getFirstWord(value);
|
|
325
|
+
|
|
326
|
+
if (invalidISBN(head)) {
|
|
327
|
+
// Don't split, if first word ain't ISBN
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const tail = value.substring(position + 1);
|
|
332
|
+
subfield.value = head; // eslint-disable-line functional/immutable-data
|
|
333
|
+
|
|
334
|
+
field.subfields.push({
|
|
335
|
+
code: 'q',
|
|
336
|
+
value: tail
|
|
337
|
+
}); // eslint-disable-line functional/immutable-data
|
|
338
|
+
}
|
|
241
339
|
|
|
242
|
-
|
|
243
|
-
|
|
340
|
+
function normalizeIsbnValue(value) {
|
|
341
|
+
const trimmedValue = getFirstWord(value); //const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...
|
|
342
|
+
|
|
343
|
+
const auditResult = _isbn.default.audit(trimmedValue);
|
|
344
|
+
|
|
345
|
+
if (!auditResult.validIsbn) {
|
|
346
|
+
return undefined;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, '');
|
|
350
|
+
|
|
351
|
+
const parsedIsbn = _isbn.default.parse(trimmedValue);
|
|
352
|
+
|
|
353
|
+
if (hyphenateISBN) {
|
|
354
|
+
// eslint-disable-line functional/no-conditional-statement
|
|
355
|
+
return numbersOnly.length === 10 ? parsedIsbn.isbn10h : parsedIsbn.isbn13h; // eslint-disable-line functional/immutable-data
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return numbersOnly.length === 10 ? parsedIsbn.isbn10 : parsedIsbn.isbn13; // eslint-disable-line functional/immutable-data
|
|
359
|
+
}
|
|
244
360
|
}
|
|
245
361
|
}
|
|
246
362
|
};
|
package/dist/isbn-issn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/isbn-issn.js"],"names":["hyphenateISBN","handleInvalid","validate","fix","description","getInvalidFields","record","get","filter","field","tag","invalidField020","subfield","subfields","find","sf","code","auditedIsbn","ISBN","audit","value","validIsbn","parsedIsbn","parse","isbn10h","isbn13h","isbn10","isbn13","invalidField022","subfieldA","undefined","subfieldZ","indexOf","subfieldAorL","subfieldY","fields","length","valid","map","name","getISSN","reduce","acc","obj","msg","messages","concat","forEach","normalizedValue","normalizeIsbnValue","push","removeSubfield","trimSpaces","trimmedValue","trimISBN","auditResult","replace"],"mappings":"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","sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* MARC record validators used in Melinda\n*\n* Copyright (c) 2014-2020 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of marc-record-validators-melinda\n*\n* marc-record-validators-melinda program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* marc-record-validators-melinda is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Lesser General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport ISBN from 'isbn3';\nimport validateISSN from '@natlibfi/issn-verify';\n\nexport default ({hyphenateISBN = false, handleInvalid = false} = {}) => {\n return {\n validate, fix,\n description: 'Validates ISBN and ISSN values'\n };\n\n function getInvalidFields(record) {\n return record.get(/^(020|022)$/u).filter(field => { // eslint-disable-line prefer-named-capture-group\n // Check ISBN:\n if (field.tag === '020') {\n if (invalidField020(field)) {\n return true;\n }\n\n const subfield = field.subfields.find(sf => sf.code === 'a');\n const auditedIsbn = ISBN.audit(subfield.value);\n if (!auditedIsbn.validIsbn) {\n return true;\n }\n // Should we refactor code by adding a function that returns legal set of values,\n // and then we compare subfield.value against that list?\n const parsedIsbn = ISBN.parse(subfield.value);\n if (hyphenateISBN) {\n return !(subfield.value === parsedIsbn.isbn10h || subfield.value === parsedIsbn.isbn13h);\n }\n\n return !(subfield.value === parsedIsbn.isbn10 || subfield.value === parsedIsbn.isbn13);\n }\n // Check ISSN:\n if (invalidField022(field)) {\n return true;\n }\n\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n return !validateISSN(subfield.value);\n });\n\n function invalidField020(field) {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n\n if (subfieldA === undefined) {\n const subfieldZ = field.subfields.find(sf => sf.code === 'z');\n if (subfieldZ !== undefined) {\n return false;\n }\n return true;\n }\n\n // If value contains space, it's not ok (it's typically something like \"1234567890 (nid.)\")\n if (subfieldA.value.indexOf(' ') > -1) {\n return true;\n }\n return false;\n }\n\n function invalidField022(field) {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL === undefined) {\n const subfieldY = field.subfields.find(sf => sf.code === 'y');\n if (subfieldY) {\n return false;\n }\n\n return true;\n }\n return false;\n }\n }\n\n function validate(record) {\n const fields = getInvalidFields(record);\n\n if (fields.length === 0) {\n return {valid: true};\n }\n\n return fields\n .map(field => {\n if (field.tag === '020') {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (subfieldA) {\n return {name: 'ISBN', value: subfieldA.value};\n }\n\n return {name: 'ISBN', value: undefined};\n }\n\n return {name: 'ISSN', value: getISSN()};\n\n function getISSN() {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL) {\n return subfieldAorL.value;\n }\n\n return undefined;\n }\n })\n .reduce((acc, obj) => {\n const {name, value} = obj;\n const msg = `${name} (${value}) is not valid`;\n\n return {...acc, messages: acc.messages.concat(msg)};\n }, {valid: false, messages: []});\n }\n\n function fix(record) {\n getInvalidFields(record).forEach(field => {\n if (field.tag === '020') {\n const subfield = field.subfields.find(sf => sf.code === 'a');\n if (subfield) {\n // ISBN is valid but is missing hyphens\n const normalizedValue = normalizeIsbnValue(subfield.value);\n if (normalizedValue !== undefined) { // eslint-disable-line functional/no-conditional-statement\n subfield.value = normalizedValue; // eslint-disable-line functional/immutable-data\n } else if (handleInvalid) { // eslint-disable-line functional/no-conditional-statement\n field.subfields.push({code: 'z', value: subfield.value}); // eslint-disable-line functional/immutable-data\n record.removeSubfield(subfield, field);\n }\n }\n } else {\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n if (subfield && handleInvalid) { // eslint-disable-line functional/no-conditional-statement\n field.subfields.push({code: 'y', value: trimSpaces(subfield.value)}); // eslint-disable-line functional/immutable-data\n record.removeSubfield(subfield, field);\n }\n }\n });\n\n function normalizeIsbnValue(value) {\n const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...\n const auditResult = ISBN.audit(trimmedValue);\n if (auditResult.validIsbn) {\n const parsedIsbn = ISBN.parse(trimmedValue);\n if (hyphenateISBN) { // eslint-disable-line functional/no-conditional-statement\n return trimmedValue.length === 10 ? parsedIsbn.isbn10h : parsedIsbn.isbn13h; // eslint-disable-line functional/immutable-data\n }\n // Just trim\n return trimmedValue.length === 10 ? parsedIsbn.isbn10 : parsedIsbn.isbn13; // eslint-disable-line functional/immutable-data\n }\n return undefined;\n }\n\n function trimSpaces(value) {\n return value.replace(/\\s/gu, '');\n }\n\n function trimISBN(value) {\n return trimSpaces(value.replace(/\\s\\D+$/gu, '')); // handle \"1234567890 (nid.)\" => \"1234567890\" as well as spaces\n }\n }\n};\n"],"file":"isbn-issn.js"}
|
|
1
|
+
{"version":3,"sources":["../src/isbn-issn.js"],"names":["hyphenateISBN","handleInvalid","validate","fix","description","stringHasSpace","str","indexOf","trimSpaces","value","replace","isMultiWord","inputString","trimmedString","getFirstWord","arr","split","invalidISBN","isbn","isbnOnly","auditedIsbn","ISBN","audit","validIsbn","invalidSubfield","subfield","code","invalidField020","field","subfields","some","sf","subfieldsIsbnRequiresHyphenation","includes","requiresHyphenation","isbn2","parsedIsbn","parse","isbn10h","isbn13h","getRelevantFields","record","fields","filter","tag","fieldsIsbnRequiresHyphenation","invalidField022","find","subfieldAorL","undefined","subfieldY","length","valid","map","subfieldA","name","subfieldZ","getISSN","reduce","acc","obj","msg","messages","concat","forEach","fixField020Subfield","push","removeSubfield","split020A","addHyphens","handleInvalidIsbn","normalizedValue","normalizeIsbnValue","head","position","tail","substring","trimmedValue","auditResult","numbersOnly","isbn10","isbn13"],"mappings":";;;;;;;AA4BA;;AACA;;;;AA7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;eACe,CAAC;AAACA,EAAAA,aAAa,GAAG,KAAjB;AAAwBC,EAAAA,aAAa,GAAG;AAAxC,IAAiD,EAAlD,KAAyD;AACtE,SAAO;AACLC,IAAAA,QADK;AACKC,IAAAA,GADL;AAELC,IAAAA,WAAW,EAAE;AAFR,GAAP;;AAKA,WAASC,cAAT,CAAwBC,GAAxB,EAA6B;AAC3B,WAAOA,GAAG,CAACC,OAAJ,CAAY,GAAZ,IAAmB,CAAC,CAA3B;AACD;;AAED,WAASC,UAAT,CAAoBC,KAApB,EAA2B;AACzB,WAAOA,KAAK,CAACC,OAAN,CAAc,OAAd,EAAuB,EAAvB,EAA2BA,OAA3B,CAAmC,OAAnC,EAA4C,EAA5C,EAAgDA,OAAhD,CAAwD,OAAxD,EAAiE,GAAjE,CAAP;AACD;;AAED,WAASC,WAAT,CAAqBC,WAArB,EAAkC;AAChC,UAAMC,aAAa,GAAGL,UAAU,CAACI,WAAD,CAAhC;AACA,WAAOP,cAAc,CAACQ,aAAD,CAArB;AACD;;AAED,WAASC,YAAT,CAAsBF,WAAtB,EAAmC;AACjC,UAAMC,aAAa,GAAGL,UAAU,CAACI,WAAD,CAAhC;AACA,UAAMG,GAAG,GAAGF,aAAa,CAACG,KAAd,CAAoB,GAApB,CAAZ;AACA,WAAOD,GAAG,CAAC,CAAD,CAAV;AACD;;AAED,WAASE,WAAT,CAAqBC,IAArB,EAA2B;AACzB,UAAMC,QAAQ,GAAGL,YAAY,CAACI,IAAD,CAA7B;;AACA,UAAME,WAAW,GAAGC,cAAKC,KAAL,CAAWH,QAAX,CAApB;;AACA,WAAO,CAACC,WAAW,CAACG,SAApB;AACD;;AAED,WAASC,eAAT,CAAyBC,QAAzB,EAAmC;AACjC,QAAIA,QAAQ,CAACC,IAAT,KAAkB,GAAtB,EAA2B;AACzB,aAAO,KAAP;AACD;;AACD,WAAOT,WAAW,CAACQ,QAAQ,CAAChB,KAAV,CAAX,IAA+BE,WAAW,CAACc,QAAQ,CAAChB,KAAV,CAAjD;AACD;;AAGD,WAASkB,eAAT,CAAyBC,KAAzB,EAAgC;AAC9B,QAAIA,KAAK,CAACC,SAAN,IAAmBD,KAAK,CAACC,SAAN,CAAgBC,IAAhB,CAAqBC,EAAE,IAAIP,eAAe,CAACO,EAAD,CAA1C,CAAvB,EAAwE;AACtE,aAAO,IAAP;AACD;;AACD,WAAO,KAAP;AACD;;AAED,WAASC,gCAAT,CAA0CP,QAA1C,EAAoD;AAClD,QAAI,CAACzB,aAAD,IAAkB,CAAC,CAAC,GAAD,EAAM,GAAN,EAAWiC,QAAX,CAAoBR,QAAQ,CAACC,IAA7B,CAAvB,EAA2D;AACzD,aAAO,KAAP;AACD;;AAED,UAAMR,IAAI,GAAGJ,YAAY,CAACW,QAAQ,CAAChB,KAAV,CAAzB;;AACA,QAAIgB,QAAQ,CAACC,IAAT,KAAkB,GAAtB,EAA2B;AACzB,aAAOQ,mBAAmB,CAAChB,IAAD,CAA1B;AACD,KARiD,CAUlD;;;AACA,QAAIA,IAAI,CAACX,OAAL,CAAa,GAAb,IAAoB,CAAC,CAAzB,EAA4B;AAC1B,aAAO,KAAP;AACD;;AACD,WAAO,CAACU,WAAW,CAACC,IAAD,CAAnB;;AAEA,aAASgB,mBAAT,CAA6BhB,IAA7B,EAAmC;AACjC,UAAI,CAAClB,aAAL,EAAoB;AAClB,eAAO,KAAP;AACD,OAHgC,CAIjC;;;AACA,YAAMmC,KAAK,GAAGrB,YAAY,CAACI,IAAD,CAA1B;;AAEA,UAAID,WAAW,CAACkB,KAAD,CAAf,EAAwB;AACtB,eAAO,KAAP;AACD;;AAED,YAAMC,UAAU,GAAGf,cAAKgB,KAAL,CAAWF,KAAX,CAAnB,CAXiC,CAYjC;;;AACA,aAAO,EAAEA,KAAK,KAAKC,UAAU,CAACE,OAArB,IAAgCH,KAAK,KAAKC,UAAU,CAACG,OAAvD,CAAP;AACD;AACF;;AAED,WAASC,iBAAT,CAA2BC,MAA3B,EAAmC;AACjC;AACA,WAAOA,MAAM,CAACC,MAAP,CAAcC,MAAd,CAAqBf,KAAK,IAAI;AACnC,UAAI,CAACA,KAAK,CAACC,SAAX,EAAsB;AACpB,eAAO,KAAP;AACD,OAHkC,CAInC;;;AACA,UAAID,KAAK,CAACgB,GAAN,KAAc,KAAlB,EAAyB;AACvB,YAAIjB,eAAe,CAACC,KAAD,CAAnB,EAA4B;AAAE;AAC5B,iBAAO,IAAP;AACD;;AACD,eAAOiB,6BAA6B,CAACjB,KAAD,CAApC;AACD,OAVkC,CAYnC;;;AACA,UAAIA,KAAK,CAACgB,GAAN,KAAc,KAAlB,EAAyB;AACvB,YAAIE,eAAe,CAAClB,KAAD,CAAnB,EAA4B;AAC1B,iBAAO,IAAP;AACD;;AAED,cAAMH,QAAQ,GAAGG,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAZ,IAAmBK,EAAE,CAACL,IAAH,KAAY,GAA1D,CAAjB;AAEA,eAAO,CAAC,yBAAaD,QAAQ,CAAChB,KAAtB,CAAR;AACD;;AACD,aAAO,KAAP;AACD,KAvBM,CAAP;;AAyBA,aAASoC,6BAAT,CAAuCjB,KAAvC,EAA8C;AAC5C,aAAOA,KAAK,CAACC,SAAN,IAAmBD,KAAK,CAACC,SAAN,CAAgBC,IAAhB,CAAqBC,EAAE,IAAIC,gCAAgC,CAACD,EAAD,CAA3D,CAA1B;AACD;;AAED,aAASe,eAAT,CAAyBlB,KAAzB,EAAgC;AAC9B,YAAMoB,YAAY,GAAGpB,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAZ,IAAmBK,EAAE,CAACL,IAAH,KAAY,GAA1D,CAArB;;AAEA,UAAIsB,YAAY,KAAKC,SAArB,EAAgC;AAC9B,cAAMC,SAAS,GAAGtB,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAvC,CAAlB;;AACA,YAAIwB,SAAJ,EAAe;AACb,iBAAO,KAAP;AACD;;AAED,eAAO,IAAP;AACD;;AACD,aAAO,KAAP;AACD;AACF;;AAED,WAAShD,QAAT,CAAkBuC,MAAlB,EAA0B;AACxB,UAAMC,MAAM,GAAGF,iBAAiB,CAACC,MAAD,CAAhC;;AAEA,QAAIC,MAAM,CAACS,MAAP,KAAkB,CAAtB,EAAyB;AACvB,aAAO;AAACC,QAAAA,KAAK,EAAE;AAAR,OAAP;AACD;;AAED,WAAOV,MAAM,CACVW,GADI,CACAzB,KAAK,IAAI;AACZ,UAAIA,KAAK,CAACgB,GAAN,KAAc,KAAlB,EAAyB;AACvB,cAAMU,SAAS,GAAG1B,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAvC,CAAlB;;AACA,YAAI4B,SAAJ,EAAe;AACb,iBAAO;AAACC,YAAAA,IAAI,EAAE,MAAP;AAAe9C,YAAAA,KAAK,EAAE6C,SAAS,CAAC7C;AAAhC,WAAP;AACD;;AACD,cAAM+C,SAAS,GAAG5B,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAvC,CAAlB;;AACA,YAAI8B,SAAJ,EAAe;AACb,iBAAO;AAACD,YAAAA,IAAI,EAAE,mBAAP;AAA4B9C,YAAAA,KAAK,EAAE+C,SAAS,CAAC/C;AAA7C,WAAP;AACD;;AAED,eAAO;AAAC8C,UAAAA,IAAI,EAAE,MAAP;AAAe9C,UAAAA,KAAK,EAAEwC;AAAtB,SAAP;AACD;;AAED,aAAO;AAACM,QAAAA,IAAI,EAAE,MAAP;AAAe9C,QAAAA,KAAK,EAAEgD,OAAO;AAA7B,OAAP;;AAEA,eAASA,OAAT,GAAmB;AACjB,cAAMT,YAAY,GAAGpB,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAZ,IAAmBK,EAAE,CAACL,IAAH,KAAY,GAA1D,CAArB;;AAEA,YAAIsB,YAAJ,EAAkB;AAChB,iBAAOA,YAAY,CAACvC,KAApB;AACD;;AAED,eAAOwC,SAAP;AACD;AACF,KA1BI,EA2BJS,MA3BI,CA2BG,CAACC,GAAD,EAAMC,GAAN,KAAc;AACpB,YAAM;AAACL,QAAAA,IAAD;AAAO9C,QAAAA;AAAP,UAAgBmD,GAAtB;AACA,YAAMC,GAAG,GAAI,GAAEN,IAAK,KAAI9C,KAAM,gBAA9B;AAEA,aAAO,EAAC,GAAGkD,GAAJ;AAASG,QAAAA,QAAQ,EAAEH,GAAG,CAACG,QAAJ,CAAaC,MAAb,CAAoBF,GAApB;AAAnB,OAAP;AACD,KAhCI,EAgCF;AAACT,MAAAA,KAAK,EAAE,KAAR;AAAeU,MAAAA,QAAQ,EAAE;AAAzB,KAhCE,CAAP;AAiCD;;AAGD,WAAS3D,GAAT,CAAasC,MAAb,EAAqB;AACnBD,IAAAA,iBAAiB,CAACC,MAAD,CAAjB,CAA0BuB,OAA1B,CAAkCpC,KAAK,IAAI;AACzC,UAAIA,KAAK,CAACgB,GAAN,KAAc,KAAlB,EAAyB;AACvBhB,QAAAA,KAAK,CAACC,SAAN,CAAgBmC,OAAhB,CAAwBvC,QAAQ,IAAIwC,mBAAmB,CAACrC,KAAD,EAAQH,QAAR,CAAvD;AACA;AACD,OAJwC,CAKzC;;;AACA,YAAMA,QAAQ,GAAGG,KAAK,CAACC,SAAN,CAAgBkB,IAAhB,CAAqBhB,EAAE,IAAIA,EAAE,CAACL,IAAH,KAAY,GAAZ,IAAmBK,EAAE,CAACL,IAAH,KAAY,GAA1D,CAAjB;;AACA,UAAID,QAAQ,IAAIxB,aAAhB,EAA+B;AAAE;AAC/B;AACA2B,QAAAA,KAAK,CAACC,SAAN,CAAgBqC,IAAhB,CAAqB;AAACxC,UAAAA,IAAI,EAAE,GAAP;AAAYjB,UAAAA,KAAK,EAAEgB,QAAQ,CAAChB;AAA5B,SAArB,EAF6B,CAE6B;;AAC1DgC,QAAAA,MAAM,CAAC0B,cAAP,CAAsB1C,QAAtB,EAAgCG,KAAhC;AACD;AACF,KAZD;;AAeA,aAASqC,mBAAT,CAA6BrC,KAA7B,EAAoCH,QAApC,EAA8C;AAC5C2C,MAAAA,SAAS,GADmC,CAC/B;;AACbC,MAAAA,UAAU,CAAC5C,QAAD,CAAV;AACA6C,MAAAA,iBAAiB,CAAC1C,KAAD,EAAQH,QAAR,CAAjB,CAH4C,CAGR;;AACpC;;AAEA,eAAS4C,UAAT,CAAoB5C,QAApB,EAA8B;AAC5B,YAAI,CAACO,gCAAgC,CAACP,QAAD,CAArC,EAAiD;AAC/C;AACD,SAH2B,CAI5B;;;AACA,cAAM8C,eAAe,GAAGC,kBAAkB,CAAC/C,QAAQ,CAAChB,KAAV,CAA1C;;AACA,YAAI8D,eAAe,KAAKtB,SAAxB,EAAmC;AAAE;AACnCxB,UAAAA,QAAQ,CAAChB,KAAT,GAAiB8D,eAAjB,CADiC,CACC;AACnC;AACF;;AAED,eAASD,iBAAT,CAA2B1C,KAA3B,EAAkCH,QAAlC,EAA4C;AAC1C,YAAIA,QAAQ,CAACC,IAAT,KAAkB,GAAlB,IAAyB,CAACzB,aAA9B,EAA6C;AAC3C;AACD;;AACD,cAAMwE,IAAI,GAAG3D,YAAY,CAACW,QAAQ,CAAChB,KAAV,CAAzB;;AACA,YAAI,CAACQ,WAAW,CAACwD,IAAD,CAAhB,EAAwB;AACtB;AACD,SAPyC,CAQ1C;;;AACA7C,QAAAA,KAAK,CAACC,SAAN,CAAgBqC,IAAhB,CAAqB;AAACxC,UAAAA,IAAI,EAAE,GAAP;AAAYjB,UAAAA,KAAK,EAAEgB,QAAQ,CAAChB;AAA5B,SAArB,EAT0C,CASgB;;AAC1DgC,QAAAA,MAAM,CAAC0B,cAAP,CAAsB1C,QAAtB,EAAgCG,KAAhC;AACD;;AAED,eAASwC,SAAT,GAAqB;AACnB;AACA,YAAI3C,QAAQ,CAACC,IAAT,KAAkB,GAAtB,EAA2B;AACzB;AACD;;AACD,cAAMjB,KAAK,GAAGD,UAAU,CAACiB,QAAQ,CAAChB,KAAV,CAAxB;AACA,cAAMiE,QAAQ,GAAGjE,KAAK,CAACF,OAAN,CAAc,GAAd,CAAjB;;AACA,YAAImE,QAAQ,KAAK,CAAC,CAAlB,EAAqB;AACnB;AACD;;AACD,cAAMD,IAAI,GAAG3D,YAAY,CAACL,KAAD,CAAzB;;AACA,YAAIQ,WAAW,CAACwD,IAAD,CAAf,EAAuB;AAAE;AACvB;AACD;;AACD,cAAME,IAAI,GAAGlE,KAAK,CAACmE,SAAN,CAAgBF,QAAQ,GAAG,CAA3B,CAAb;AACAjD,QAAAA,QAAQ,CAAChB,KAAT,GAAiBgE,IAAjB,CAfmB,CAeI;;AACvB7C,QAAAA,KAAK,CAACC,SAAN,CAAgBqC,IAAhB,CAAqB;AAACxC,UAAAA,IAAI,EAAE,GAAP;AAAYjB,UAAAA,KAAK,EAAEkE;AAAnB,SAArB,EAhBmB,CAgB6B;AACjD;;AAED,eAASH,kBAAT,CAA4B/D,KAA5B,EAAmC;AACjC,cAAMoE,YAAY,GAAG/D,YAAY,CAACL,KAAD,CAAjC,CADiC,CAEjC;;AACA,cAAMqE,WAAW,GAAGzD,cAAKC,KAAL,CAAWuD,YAAX,CAApB;;AACA,YAAI,CAACC,WAAW,CAACvD,SAAjB,EAA4B;AAC1B,iBAAO0B,SAAP;AACD;;AACD,cAAM8B,WAAW,GAAGF,YAAY,CAACnE,OAAb,CAAqB,aAArB,EAAoC,EAApC,CAApB;;AACA,cAAM0B,UAAU,GAAGf,cAAKgB,KAAL,CAAWwC,YAAX,CAAnB;;AACA,YAAI7E,aAAJ,EAAmB;AAAE;AACnB,iBAAO+E,WAAW,CAAC5B,MAAZ,KAAuB,EAAvB,GAA4Bf,UAAU,CAACE,OAAvC,GAAiDF,UAAU,CAACG,OAAnE,CADiB,CAC2D;AAC7E;;AACD,eAAOwC,WAAW,CAAC5B,MAAZ,KAAuB,EAAvB,GAA4Bf,UAAU,CAAC4C,MAAvC,GAAgD5C,UAAU,CAAC6C,MAAlE,CAZiC,CAYyC;AAC3E;AACF;AACF;AACF,C","sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* MARC record validators used in Melinda\n*\n* Copyright (c) 2014-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of marc-record-validators-melinda\n*\n* marc-record-validators-melinda program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* marc-record-validators-melinda is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Lesser General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport ISBN from 'isbn3';\nimport validateISSN from '@natlibfi/issn-verify';\n\n// handleInvalid: move invalid 020$a to 020$z, and invalid 022$a to 022$y\nexport default ({hyphenateISBN = false, handleInvalid = false} = {}) => {\n return {\n validate, fix,\n description: 'Validates ISBN and ISSN values'\n };\n\n function stringHasSpace(str) {\n return str.indexOf(' ') > -1;\n }\n\n function trimSpaces(value) {\n return value.replace(/^\\s+/u, '').replace(/\\s+$/u, '').replace(/\\s+/gu, ' ');\n }\n\n function isMultiWord(inputString) {\n const trimmedString = trimSpaces(inputString);\n return stringHasSpace(trimmedString);\n }\n\n function getFirstWord(inputString) {\n const trimmedString = trimSpaces(inputString);\n const arr = trimmedString.split(' ');\n return arr[0];\n }\n\n function invalidISBN(isbn) {\n const isbnOnly = getFirstWord(isbn);\n const auditedIsbn = ISBN.audit(isbnOnly);\n return !auditedIsbn.validIsbn;\n }\n\n function invalidSubfield(subfield) {\n if (subfield.code !== 'a') {\n return false;\n }\n return invalidISBN(subfield.value) || isMultiWord(subfield.value);\n }\n\n\n function invalidField020(field) {\n if (field.subfields && field.subfields.some(sf => invalidSubfield(sf))) {\n return true;\n }\n return false;\n }\n\n function subfieldsIsbnRequiresHyphenation(subfield) {\n if (!hyphenateISBN || !['a', 'z'].includes(subfield.code)) {\n return false;\n }\n\n const isbn = getFirstWord(subfield.value);\n if (subfield.code === 'a') {\n return requiresHyphenation(isbn);\n }\n\n // $z is a bit hacky: hyphenation is required only iff valid and no '-' chars\n if (isbn.indexOf('-') > -1) {\n return false;\n }\n return !invalidISBN(isbn);\n\n function requiresHyphenation(isbn) {\n if (!hyphenateISBN) {\n return false;\n }\n // Handle old notation such as \"978-952-396-001-5 (nid.)\"\n const isbn2 = getFirstWord(isbn);\n\n if (invalidISBN(isbn2)) {\n return false;\n }\n\n const parsedIsbn = ISBN.parse(isbn2);\n // Return true only if existing ISBN is a valid and hyphenated 10 or 13 digit ISBN:\n return !(isbn2 === parsedIsbn.isbn10h || isbn2 === parsedIsbn.isbn13h);\n }\n }\n\n function getRelevantFields(record) {\n //return record.get(/^(?:020|022)$/u).filter(field => {\n return record.fields.filter(field => {\n if (!field.subfields) {\n return false;\n }\n // Check ISBN:\n if (field.tag === '020') {\n if (invalidField020(field)) { // checks multiwordness\n return true;\n }\n return fieldsIsbnRequiresHyphenation(field);\n }\n\n // Check ISSN:\n if (field.tag === '022') {\n if (invalidField022(field)) {\n return true;\n }\n\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n return !validateISSN(subfield.value);\n }\n return false;\n });\n\n function fieldsIsbnRequiresHyphenation(field) {\n return field.subfields && field.subfields.some(sf => subfieldsIsbnRequiresHyphenation(sf));\n }\n\n function invalidField022(field) {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL === undefined) {\n const subfieldY = field.subfields.find(sf => sf.code === 'y');\n if (subfieldY) {\n return false;\n }\n\n return true;\n }\n return false;\n }\n }\n\n function validate(record) {\n const fields = getRelevantFields(record);\n\n if (fields.length === 0) {\n return {valid: true};\n }\n\n return fields\n .map(field => {\n if (field.tag === '020') {\n const subfieldA = field.subfields.find(sf => sf.code === 'a');\n if (subfieldA) {\n return {name: 'ISBN', value: subfieldA.value};\n }\n const subfieldZ = field.subfields.find(sf => sf.code === 'z');\n if (subfieldZ) {\n return {name: 'ISBN (subfield Z)', value: subfieldZ.value};\n }\n\n return {name: 'ISBN', value: undefined};\n }\n\n return {name: 'ISSN', value: getISSN()};\n\n function getISSN() {\n const subfieldAorL = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n\n if (subfieldAorL) {\n return subfieldAorL.value;\n }\n\n return undefined;\n }\n })\n .reduce((acc, obj) => {\n const {name, value} = obj;\n const msg = `${name} (${value}) is not valid`;\n\n return {...acc, messages: acc.messages.concat(msg)};\n }, {valid: false, messages: []});\n }\n\n\n function fix(record) {\n getRelevantFields(record).forEach(field => {\n if (field.tag === '020') {\n field.subfields.forEach(subfield => fixField020Subfield(field, subfield));\n return;\n }\n // 022 ISSN:\n const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');\n if (subfield && handleInvalid) { // eslint-disable-line functional/no-conditional-statement\n // $a/$l => $y (bit overkill to add $z and remove $a/$l instead of just renaming)\n field.subfields.push({code: 'y', value: subfield.value}); // eslint-disable-line functional/immutable-data\n record.removeSubfield(subfield, field);\n }\n });\n\n\n function fixField020Subfield(field, subfield) {\n split020A(); // subfield and field are in the scope\n addHyphens(subfield);\n handleInvalidIsbn(field, subfield); // remove 020$a, add 020$z, Do this last, as it uses deletion\n return;\n\n function addHyphens(subfield) {\n if (!subfieldsIsbnRequiresHyphenation(subfield)) {\n return;\n }\n // ISBN is valid but is missing hyphens\n const normalizedValue = normalizeIsbnValue(subfield.value);\n if (normalizedValue !== undefined) { // eslint-disable-line functional/no-conditional-statement\n subfield.value = normalizedValue; // eslint-disable-line functional/immutable-data\n }\n }\n\n function handleInvalidIsbn(field, subfield) {\n if (subfield.code !== 'a' || !handleInvalid) {\n return;\n }\n const head = getFirstWord(subfield.value);\n if (!invalidISBN(head)) {\n return;\n }\n // $a => $z (bit overkill to add $z and remove $a instead of just renaming, but too lazy to fix/test thorougly)\n field.subfields.push({code: 'z', value: subfield.value}); // eslint-disable-line functional/immutable-data\n record.removeSubfield(subfield, field);\n }\n\n function split020A() {\n // Move non-initial words from $a to $q:\n if (subfield.code !== 'a') {\n return;\n }\n const value = trimSpaces(subfield.value);\n const position = value.indexOf(' ');\n if (position === -1) {\n return;\n }\n const head = getFirstWord(value);\n if (invalidISBN(head)) { // Don't split, if first word ain't ISBN\n return;\n }\n const tail = value.substring(position + 1);\n subfield.value = head; // eslint-disable-line functional/immutable-data\n field.subfields.push({code: 'q', value: tail}); // eslint-disable-line functional/immutable-data\n }\n\n function normalizeIsbnValue(value) {\n const trimmedValue = getFirstWord(value);\n //const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...\n const auditResult = ISBN.audit(trimmedValue);\n if (!auditResult.validIsbn) {\n return undefined;\n }\n const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, '');\n const parsedIsbn = ISBN.parse(trimmedValue);\n if (hyphenateISBN) { // eslint-disable-line functional/no-conditional-statement\n return numbersOnly.length === 10 ? parsedIsbn.isbn10h : parsedIsbn.isbn13h; // eslint-disable-line functional/immutable-data\n }\n return numbersOnly.length === 10 ? parsedIsbn.isbn10 : parsedIsbn.isbn13; // eslint-disable-line functional/immutable-data\n }\n }\n }\n};\n"],"file":"isbn-issn.js"}
|