@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/src/isbn-issn.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* MARC record validators used in Melinda
|
|
6
6
|
*
|
|
7
|
-
* Copyright (c) 2014-
|
|
7
|
+
* Copyright (c) 2014-2022 University Of Helsinki (The National Library Of Finland)
|
|
8
8
|
*
|
|
9
9
|
* This file is part of marc-record-validators-melinda
|
|
10
10
|
*
|
|
@@ -29,60 +29,115 @@
|
|
|
29
29
|
import ISBN from 'isbn3';
|
|
30
30
|
import validateISSN from '@natlibfi/issn-verify';
|
|
31
31
|
|
|
32
|
+
// handleInvalid: move invalid 020$a to 020$z, and invalid 022$a to 022$y
|
|
32
33
|
export default ({hyphenateISBN = false, handleInvalid = false} = {}) => {
|
|
33
34
|
return {
|
|
34
35
|
validate, fix,
|
|
35
36
|
description: 'Validates ISBN and ISSN values'
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
function
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
if (field.tag === '020') {
|
|
42
|
-
if (invalidField020(field)) {
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
39
|
+
function stringHasSpace(str) {
|
|
40
|
+
return str.indexOf(' ') > -1;
|
|
41
|
+
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
// Should we refactor code by adding a function that returns legal set of values,
|
|
52
|
-
// and then we compare subfield.value against that list?
|
|
53
|
-
const parsedIsbn = ISBN.parse(subfield.value);
|
|
54
|
-
if (hyphenateISBN) {
|
|
55
|
-
return !(subfield.value === parsedIsbn.isbn10h || subfield.value === parsedIsbn.isbn13h);
|
|
56
|
-
}
|
|
43
|
+
function trimSpaces(value) {
|
|
44
|
+
return value.replace(/^\s+/u, '').replace(/\s+$/u, '').replace(/\s+/gu, ' ');
|
|
45
|
+
}
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
47
|
+
function isMultiWord(inputString) {
|
|
48
|
+
const trimmedString = trimSpaces(inputString);
|
|
49
|
+
return stringHasSpace(trimmedString);
|
|
50
|
+
}
|
|
64
51
|
|
|
65
|
-
|
|
52
|
+
function getFirstWord(inputString) {
|
|
53
|
+
const trimmedString = trimSpaces(inputString);
|
|
54
|
+
const arr = trimmedString.split(' ');
|
|
55
|
+
return arr[0];
|
|
56
|
+
}
|
|
66
57
|
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
function invalidISBN(isbn) {
|
|
59
|
+
const isbnOnly = getFirstWord(isbn);
|
|
60
|
+
const auditedIsbn = ISBN.audit(isbnOnly);
|
|
61
|
+
return !auditedIsbn.validIsbn;
|
|
62
|
+
}
|
|
69
63
|
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
function invalidSubfield(subfield) {
|
|
65
|
+
if (subfield.code !== 'a') {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return invalidISBN(subfield.value) || isMultiWord(subfield.value);
|
|
69
|
+
}
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
|
|
72
|
+
function invalidField020(field) {
|
|
73
|
+
if (field.subfields && field.subfields.some(sf => invalidSubfield(sf))) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function subfieldsIsbnRequiresHyphenation(subfield) {
|
|
80
|
+
if (!hyphenateISBN || !['a', 'z'].includes(subfield.code)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const isbn = getFirstWord(subfield.value);
|
|
85
|
+
if (subfield.code === 'a') {
|
|
86
|
+
return requiresHyphenation(isbn);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// $z is a bit hacky: hyphenation is required only iff valid and no '-' chars
|
|
90
|
+
if (isbn.indexOf('-') > -1) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
return !invalidISBN(isbn);
|
|
94
|
+
|
|
95
|
+
function requiresHyphenation(isbn) {
|
|
96
|
+
if (!hyphenateISBN) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
// Handle old notation such as "978-952-396-001-5 (nid.)"
|
|
100
|
+
const isbn2 = getFirstWord(isbn);
|
|
101
|
+
|
|
102
|
+
if (invalidISBN(isbn2)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const parsedIsbn = ISBN.parse(isbn2);
|
|
107
|
+
// Return true only if existing ISBN is a valid and hyphenated 10 or 13 digit ISBN:
|
|
108
|
+
return !(isbn2 === parsedIsbn.isbn10h || isbn2 === parsedIsbn.isbn13h);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getRelevantFields(record) {
|
|
113
|
+
//return record.get(/^(?:020|022)$/u).filter(field => {
|
|
114
|
+
return record.fields.filter(field => {
|
|
115
|
+
if (!field.subfields) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
// Check ISBN:
|
|
119
|
+
if (field.tag === '020') {
|
|
120
|
+
if (invalidField020(field)) { // checks multiwordness
|
|
121
|
+
return true;
|
|
77
122
|
}
|
|
78
|
-
return
|
|
123
|
+
return fieldsIsbnRequiresHyphenation(field);
|
|
79
124
|
}
|
|
80
125
|
|
|
81
|
-
//
|
|
82
|
-
if (
|
|
83
|
-
|
|
126
|
+
// Check ISSN:
|
|
127
|
+
if (field.tag === '022') {
|
|
128
|
+
if (invalidField022(field)) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');
|
|
133
|
+
|
|
134
|
+
return !validateISSN(subfield.value);
|
|
84
135
|
}
|
|
85
136
|
return false;
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
function fieldsIsbnRequiresHyphenation(field) {
|
|
140
|
+
return field.subfields && field.subfields.some(sf => subfieldsIsbnRequiresHyphenation(sf));
|
|
86
141
|
}
|
|
87
142
|
|
|
88
143
|
function invalidField022(field) {
|
|
@@ -101,7 +156,7 @@ export default ({hyphenateISBN = false, handleInvalid = false} = {}) => {
|
|
|
101
156
|
}
|
|
102
157
|
|
|
103
158
|
function validate(record) {
|
|
104
|
-
const fields =
|
|
159
|
+
const fields = getRelevantFields(record);
|
|
105
160
|
|
|
106
161
|
if (fields.length === 0) {
|
|
107
162
|
return {valid: true};
|
|
@@ -114,6 +169,10 @@ export default ({hyphenateISBN = false, handleInvalid = false} = {}) => {
|
|
|
114
169
|
if (subfieldA) {
|
|
115
170
|
return {name: 'ISBN', value: subfieldA.value};
|
|
116
171
|
}
|
|
172
|
+
const subfieldZ = field.subfields.find(sf => sf.code === 'z');
|
|
173
|
+
if (subfieldZ) {
|
|
174
|
+
return {name: 'ISBN (subfield Z)', value: subfieldZ.value};
|
|
175
|
+
}
|
|
117
176
|
|
|
118
177
|
return {name: 'ISBN', value: undefined};
|
|
119
178
|
}
|
|
@@ -138,49 +197,86 @@ export default ({hyphenateISBN = false, handleInvalid = false} = {}) => {
|
|
|
138
197
|
}, {valid: false, messages: []});
|
|
139
198
|
}
|
|
140
199
|
|
|
200
|
+
|
|
141
201
|
function fix(record) {
|
|
142
|
-
|
|
202
|
+
getRelevantFields(record).forEach(field => {
|
|
143
203
|
if (field.tag === '020') {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
204
|
+
field.subfields.forEach(subfield => fixField020Subfield(field, subfield));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// 022 ISSN:
|
|
208
|
+
const subfield = field.subfields.find(sf => sf.code === 'a' || sf.code === 'l');
|
|
209
|
+
if (subfield && handleInvalid) { // eslint-disable-line functional/no-conditional-statement
|
|
210
|
+
// $a/$l => $y (bit overkill to add $z and remove $a/$l instead of just renaming)
|
|
211
|
+
field.subfields.push({code: 'y', value: subfield.value}); // eslint-disable-line functional/immutable-data
|
|
212
|
+
record.removeSubfield(subfield, field);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
function fixField020Subfield(field, subfield) {
|
|
218
|
+
split020A(); // subfield and field are in the scope
|
|
219
|
+
addHyphens(subfield);
|
|
220
|
+
handleInvalidIsbn(field, subfield); // remove 020$a, add 020$z, Do this last, as it uses deletion
|
|
221
|
+
return;
|
|
222
|
+
|
|
223
|
+
function addHyphens(subfield) {
|
|
224
|
+
if (!subfieldsIsbnRequiresHyphenation(subfield)) {
|
|
225
|
+
return;
|
|
154
226
|
}
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
record.removeSubfield(subfield, field);
|
|
227
|
+
// ISBN is valid but is missing hyphens
|
|
228
|
+
const normalizedValue = normalizeIsbnValue(subfield.value);
|
|
229
|
+
if (normalizedValue !== undefined) { // eslint-disable-line functional/no-conditional-statement
|
|
230
|
+
subfield.value = normalizedValue; // eslint-disable-line functional/immutable-data
|
|
160
231
|
}
|
|
161
232
|
}
|
|
162
|
-
});
|
|
163
233
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
if (
|
|
170
|
-
return
|
|
234
|
+
function handleInvalidIsbn(field, subfield) {
|
|
235
|
+
if (subfield.code !== 'a' || !handleInvalid) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const head = getFirstWord(subfield.value);
|
|
239
|
+
if (!invalidISBN(head)) {
|
|
240
|
+
return;
|
|
171
241
|
}
|
|
172
|
-
//
|
|
173
|
-
|
|
242
|
+
// $a => $z (bit overkill to add $z and remove $a instead of just renaming, but too lazy to fix/test thorougly)
|
|
243
|
+
field.subfields.push({code: 'z', value: subfield.value}); // eslint-disable-line functional/immutable-data
|
|
244
|
+
record.removeSubfield(subfield, field);
|
|
174
245
|
}
|
|
175
|
-
return undefined;
|
|
176
|
-
}
|
|
177
246
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
247
|
+
function split020A() {
|
|
248
|
+
// Move non-initial words from $a to $q:
|
|
249
|
+
if (subfield.code !== 'a') {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const value = trimSpaces(subfield.value);
|
|
253
|
+
const position = value.indexOf(' ');
|
|
254
|
+
if (position === -1) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const head = getFirstWord(value);
|
|
258
|
+
if (invalidISBN(head)) { // Don't split, if first word ain't ISBN
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const tail = value.substring(position + 1);
|
|
262
|
+
subfield.value = head; // eslint-disable-line functional/immutable-data
|
|
263
|
+
field.subfields.push({code: 'q', value: tail}); // eslint-disable-line functional/immutable-data
|
|
264
|
+
}
|
|
181
265
|
|
|
182
|
-
|
|
183
|
-
|
|
266
|
+
function normalizeIsbnValue(value) {
|
|
267
|
+
const trimmedValue = getFirstWord(value);
|
|
268
|
+
//const trimmedValue = trimISBN(value); // NB! This might lose information that should be stored in $q...
|
|
269
|
+
const auditResult = ISBN.audit(trimmedValue);
|
|
270
|
+
if (!auditResult.validIsbn) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
const numbersOnly = trimmedValue.replace(/[^0-9Xx]+/ug, '');
|
|
274
|
+
const parsedIsbn = ISBN.parse(trimmedValue);
|
|
275
|
+
if (hyphenateISBN) { // eslint-disable-line functional/no-conditional-statement
|
|
276
|
+
return numbersOnly.length === 10 ? parsedIsbn.isbn10h : parsedIsbn.isbn13h; // eslint-disable-line functional/immutable-data
|
|
277
|
+
}
|
|
278
|
+
return numbersOnly.length === 10 ? parsedIsbn.isbn10 : parsedIsbn.isbn13; // eslint-disable-line functional/immutable-data
|
|
279
|
+
}
|
|
184
280
|
}
|
|
185
281
|
}
|
|
186
282
|
};
|
package/src/isbn-issn.spec.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* MARC record validators used in Melinda
|
|
6
6
|
*
|
|
7
|
-
* Copyright (c) 2014-
|
|
7
|
+
* Copyright (c) 2014-2022 University Of Helsinki (The National Library Of Finland)
|
|
8
8
|
*
|
|
9
9
|
* This file is part of marc-record-validators-melinda
|
|
10
10
|
*
|
|
@@ -60,6 +60,7 @@ describe('isbn-issn', () => {
|
|
|
60
60
|
ind2: ' ',
|
|
61
61
|
subfields: [{code: 'a', value: '90-6831-372-X'}]
|
|
62
62
|
},
|
|
63
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '978-600-377-017-1'}]},
|
|
63
64
|
{
|
|
64
65
|
tag: '022',
|
|
65
66
|
ind1: ' ',
|
|
@@ -83,6 +84,12 @@ describe('isbn-issn', () => {
|
|
|
83
84
|
ind2: ' ',
|
|
84
85
|
subfields: [{code: 'a', value: 'foo'}]
|
|
85
86
|
},
|
|
87
|
+
{
|
|
88
|
+
tag: '020',
|
|
89
|
+
ind1: ' ',
|
|
90
|
+
ind2: ' ',
|
|
91
|
+
subfields: [{code: 'a', value: '90-68-31-372-X'}] // contains an extra hyphen
|
|
92
|
+
},
|
|
86
93
|
{
|
|
87
94
|
tag: '022',
|
|
88
95
|
ind1: ' ',
|
|
@@ -101,7 +108,7 @@ describe('isbn-issn', () => {
|
|
|
101
108
|
});
|
|
102
109
|
});
|
|
103
110
|
|
|
104
|
-
it('
|
|
111
|
+
it('020 field without $a and $z is ok in this context (= no invalid ISBNs)', async () => {
|
|
105
112
|
const validator = await validatorFactory();
|
|
106
113
|
const record = new MarcRecord({
|
|
107
114
|
fields: [
|
|
@@ -116,7 +123,7 @@ describe('isbn-issn', () => {
|
|
|
116
123
|
const result = await validator.validate(record);
|
|
117
124
|
|
|
118
125
|
expect(result).to.eql({
|
|
119
|
-
valid:
|
|
126
|
+
valid: true
|
|
120
127
|
});
|
|
121
128
|
});
|
|
122
129
|
|
|
@@ -139,16 +146,10 @@ describe('isbn-issn', () => {
|
|
|
139
146
|
});
|
|
140
147
|
});
|
|
141
148
|
|
|
142
|
-
it('Finds the record invalid (
|
|
149
|
+
it('Finds the record invalid (reason: multiword)', async () => {
|
|
143
150
|
const validator = await validatorFactory();
|
|
144
151
|
const record = new MarcRecord({
|
|
145
152
|
fields: [
|
|
146
|
-
{
|
|
147
|
-
tag: '020',
|
|
148
|
-
ind1: ' ',
|
|
149
|
-
ind2: ' ',
|
|
150
|
-
subfields: [{code: 'a', value: ' 9789519155470'}]
|
|
151
|
-
},
|
|
152
153
|
{
|
|
153
154
|
tag: '020',
|
|
154
155
|
ind1: ' ',
|
|
@@ -159,12 +160,7 @@ describe('isbn-issn', () => {
|
|
|
159
160
|
});
|
|
160
161
|
const result = await validator.validate(record);
|
|
161
162
|
|
|
162
|
-
expect(result).to.eql({
|
|
163
|
-
valid: false, messages: [
|
|
164
|
-
'ISBN ( 9789519155470) is not valid',
|
|
165
|
-
'ISBN (978-600-377-017-1 (nid.)) is not valid'
|
|
166
|
-
]
|
|
167
|
-
});
|
|
163
|
+
expect(result).to.eql({valid: false, messages: ['ISBN (978-600-377-017-1 (nid.)) is not valid']});
|
|
168
164
|
});
|
|
169
165
|
|
|
170
166
|
it('Finds the record invalid (ISSN in \'l\'-subfield)', async () => {
|
|
@@ -205,6 +201,12 @@ describe('isbn-issn', () => {
|
|
|
205
201
|
ind2: ' ',
|
|
206
202
|
subfields: [{code: 'a', value: '9789519155470'}]
|
|
207
203
|
},
|
|
204
|
+
{
|
|
205
|
+
tag: '020',
|
|
206
|
+
ind1: ' ',
|
|
207
|
+
ind2: ' ',
|
|
208
|
+
subfields: [{code: 'a', value: '9068-31-372-X'}] // legal digits, but bad hyphenation
|
|
209
|
+
},
|
|
208
210
|
{
|
|
209
211
|
tag: '020',
|
|
210
212
|
ind1: ' ',
|
|
@@ -217,6 +219,7 @@ describe('isbn-issn', () => {
|
|
|
217
219
|
|
|
218
220
|
expect(result).to.eql({valid: false, messages: [
|
|
219
221
|
'ISBN (9789519155470) is not valid',
|
|
222
|
+
'ISBN (9068-31-372-X) is not valid',
|
|
220
223
|
'ISBN (386006004X) is not valid'
|
|
221
224
|
]});
|
|
222
225
|
});
|
|
@@ -237,7 +240,10 @@ describe('isbn-issn', () => {
|
|
|
237
240
|
{
|
|
238
241
|
tag: '020', ind1: ' ', ind2: ' ',
|
|
239
242
|
subfields: [{code: 'a', value: 'crappy val'}]
|
|
240
|
-
}
|
|
243
|
+
},
|
|
244
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '97895234216609'}]},
|
|
245
|
+
// Just a sanity check due to earlier issues:
|
|
246
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '97895234216609'}]}
|
|
241
247
|
]
|
|
242
248
|
});
|
|
243
249
|
|
|
@@ -245,7 +251,9 @@ describe('isbn-issn', () => {
|
|
|
245
251
|
|
|
246
252
|
expect(record.fields).to.eql([
|
|
247
253
|
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: 'foo'}]},
|
|
248
|
-
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: 'crappy val'}]}
|
|
254
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: 'crappy val'}]},
|
|
255
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '97895234216609'}]},
|
|
256
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '97895234216609'}]}
|
|
249
257
|
]);
|
|
250
258
|
});
|
|
251
259
|
|
|
@@ -303,15 +311,16 @@ describe('isbn-issn', () => {
|
|
|
303
311
|
tag: '020',
|
|
304
312
|
ind1: ' ',
|
|
305
313
|
ind2: ' ',
|
|
306
|
-
subfields: [{code: 'a', value: '9786003770171 (
|
|
314
|
+
subfields: [{code: 'a', value: '9786003770171 (nidottu)'}]
|
|
307
315
|
}
|
|
308
316
|
]
|
|
309
317
|
});
|
|
310
318
|
await validator.fix(record);
|
|
311
319
|
|
|
312
320
|
expect(record.fields).to.eql([
|
|
313
|
-
|
|
314
|
-
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '9786003770171'}]}
|
|
321
|
+
// NB! Initial space does not need to be removed. It's crap, but not this fixer's crap.
|
|
322
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: ' 9786003770171'}]},
|
|
323
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '9786003770171'}, {code: 'q', value: '(nidottu)'}]}
|
|
315
324
|
]);
|
|
316
325
|
});
|
|
317
326
|
|
|
@@ -323,7 +332,11 @@ describe('isbn-issn', () => {
|
|
|
323
332
|
tag: '020',
|
|
324
333
|
ind1: ' ',
|
|
325
334
|
ind2: ' ',
|
|
326
|
-
subfields: [
|
|
335
|
+
subfields: [
|
|
336
|
+
{code: 'a', value: '9786003770171 (nid.)'},
|
|
337
|
+
{code: 'z', value: '9786003770171 (nid.)'},
|
|
338
|
+
{code: 'z', value: 'foo bar'}
|
|
339
|
+
]
|
|
327
340
|
}
|
|
328
341
|
]
|
|
329
342
|
});
|
|
@@ -331,12 +344,52 @@ describe('isbn-issn', () => {
|
|
|
331
344
|
|
|
332
345
|
expect(record.fields).to.eql([
|
|
333
346
|
{
|
|
334
|
-
tag: '020',
|
|
347
|
+
tag: '020',
|
|
348
|
+
ind1: ' ',
|
|
349
|
+
ind2: ' ',
|
|
350
|
+
subfields: [
|
|
351
|
+
{code: 'a', value: '978-600-377-017-1'},
|
|
352
|
+
{code: 'z', value: '978-600-377-017-1'},
|
|
353
|
+
{code: 'z', value: 'foo bar'},
|
|
354
|
+
// NB! Technically $q should come before $z subfields, but this is good enough.
|
|
355
|
+
{code: 'q', value: '(nid.)'}
|
|
356
|
+
]
|
|
335
357
|
}
|
|
336
358
|
]);
|
|
337
359
|
});
|
|
338
360
|
|
|
339
|
-
it('
|
|
361
|
+
it('No relevant data', async () => {
|
|
362
|
+
const validator = await validatorFactory({hyphenateISBN: true});
|
|
363
|
+
const record = new MarcRecord({
|
|
364
|
+
fields: [
|
|
365
|
+
{
|
|
366
|
+
tag: '005',
|
|
367
|
+
value: 'whatever'
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
tag: '020',
|
|
371
|
+
ind1: ' ',
|
|
372
|
+
ind2: ' ',
|
|
373
|
+
subfields: [{code: 'q', value: 'sidottu'}]
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
tag: '024',
|
|
377
|
+
ind1: ' ',
|
|
378
|
+
ind2: ' ',
|
|
379
|
+
subfields: [{code: 'a', value: ' 9786003770171'}]
|
|
380
|
+
}
|
|
381
|
+
]
|
|
382
|
+
});
|
|
383
|
+
await validator.fix(record);
|
|
384
|
+
|
|
385
|
+
expect(record.fields).to.eql([
|
|
386
|
+
{tag: '005', value: 'whatever'},
|
|
387
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'q', value: 'sidottu'}]},
|
|
388
|
+
{tag: '024', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: ' 9786003770171'}]}
|
|
389
|
+
]);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('Add hyphens to ISBN', async () => {
|
|
340
393
|
const validator = await validatorFactory({hyphenateISBN: true});
|
|
341
394
|
const record = new MarcRecord({
|
|
342
395
|
fields: [
|
|
@@ -348,10 +401,21 @@ describe('isbn-issn', () => {
|
|
|
348
401
|
tag: '020', ind1: ' ', ind2: ' ',
|
|
349
402
|
subfields: [{code: 'a', value: '917153086X'}]
|
|
350
403
|
},
|
|
404
|
+
{
|
|
405
|
+
tag: '020',
|
|
406
|
+
ind1: ' ',
|
|
407
|
+
ind2: ' ',
|
|
408
|
+
subfields: [{code: 'a', value: '9068-31-372-X'}] // legal digits, but bad hyphenation
|
|
409
|
+
},
|
|
351
410
|
{
|
|
352
411
|
tag: '020', ind1: ' ', ind2: ' ',
|
|
353
412
|
subfields: [{code: 'a', value: '386006004X (nid.)'}]
|
|
354
|
-
}
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
tag: '020', ind1: ' ', ind2: ' ',
|
|
416
|
+
subfields: [{code: 'z', value: '9789916605325'}]
|
|
417
|
+
},
|
|
418
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '9789916605325 (sid.)'}]}
|
|
355
419
|
]
|
|
356
420
|
});
|
|
357
421
|
|
|
@@ -360,7 +424,10 @@ describe('isbn-issn', () => {
|
|
|
360
424
|
expect(record.fields).to.eql([
|
|
361
425
|
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '978-9916-605-32-5'}]},
|
|
362
426
|
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '91-7153-086-X'}]},
|
|
363
|
-
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '
|
|
427
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '90-6831-372-X'}]}, // corrected hyphens
|
|
428
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'a', value: '3-86006-004-X'}, {code: 'q', value: '(nid.)'}]},
|
|
429
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '978-9916-605-32-5'}]},
|
|
430
|
+
{tag: '020', ind1: ' ', ind2: ' ', subfields: [{code: 'z', value: '978-9916-605-32-5'}]}
|
|
364
431
|
]);
|
|
365
432
|
});
|
|
366
433
|
});
|